claude-pro-minmax 1.0.0
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/CLAUDE.md +60 -0
- package/.claude/agents/README.ko.md +210 -0
- package/.claude/agents/README.md +210 -0
- package/.claude/agents/builder.md +96 -0
- package/.claude/agents/dplanner.md +58 -0
- package/.claude/agents/planner.md +52 -0
- package/.claude/agents/reviewer.md +69 -0
- package/.claude/commands/README.ko.md +381 -0
- package/.claude/commands/README.md +381 -0
- package/.claude/commands/analyze-failures.md +49 -0
- package/.claude/commands/compact-phase.md +75 -0
- package/.claude/commands/do-opus.md +43 -0
- package/.claude/commands/do-sonnet.md +43 -0
- package/.claude/commands/do.md +56 -0
- package/.claude/commands/dplan.md +36 -0
- package/.claude/commands/learn.md +64 -0
- package/.claude/commands/llms-txt.md +50 -0
- package/.claude/commands/load-context.md +46 -0
- package/.claude/commands/plan.md +62 -0
- package/.claude/commands/review.md +55 -0
- package/.claude/commands/session-load.md +61 -0
- package/.claude/commands/session-save.md +79 -0
- package/.claude/commands/watch.md +58 -0
- package/.claude/contexts/README.ko.md +94 -0
- package/.claude/contexts/README.md +94 -0
- package/.claude/contexts/backend-context.md +23 -0
- package/.claude/contexts/frontend-context.md +24 -0
- package/.claude/rules/README.ko.md +98 -0
- package/.claude/rules/README.md +98 -0
- package/.claude/rules/code-style.md +21 -0
- package/.claude/rules/critical-actions.md +34 -0
- package/.claude/rules/security.md +13 -0
- package/.claude/sessions/2025-01-27-auth-jwt-refresh.md +32 -0
- package/.claude/sessions/README.ko.md +195 -0
- package/.claude/sessions/README.md +195 -0
- package/.claude/settings.json +167 -0
- package/.claude/settings.local.example.json +3 -0
- package/.claude/skills/README.ko.md +60 -0
- package/.claude/skills/README.md +60 -0
- package/.claude/skills/cli-wrappers/SKILL.md +38 -0
- package/.claude/skills/cli-wrappers/references/github-cli.md +18 -0
- package/.claude/skills/cli-wrappers/references/mgrep.md +18 -0
- package/.claude/skills/learned/README.ko.md +64 -0
- package/.claude/skills/learned/README.md +64 -0
- package/.claude.json +28 -0
- package/.claudeignore +17 -0
- package/LICENSE +21 -0
- package/README.ko.md +441 -0
- package/README.md +441 -0
- package/bin/cpmm.js +171 -0
- package/install.sh +154 -0
- package/package.json +59 -0
- package/scripts/README.ko.md +150 -0
- package/scripts/README.md +150 -0
- package/scripts/analyze-failures.sh +145 -0
- package/scripts/build.sh +34 -0
- package/scripts/claude_command_smoke.sh +116 -0
- package/scripts/commit.sh +7 -0
- package/scripts/create-branch.sh +14 -0
- package/scripts/hooks/README.ko.md +117 -0
- package/scripts/hooks/README.md +118 -0
- package/scripts/hooks/compact-suggest.sh +52 -0
- package/scripts/hooks/critical-action-check.sh +68 -0
- package/scripts/hooks/notification.sh +47 -0
- package/scripts/hooks/post-edit-format.sh +39 -0
- package/scripts/hooks/pre-compact.sh +55 -0
- package/scripts/hooks/readonly-check.sh +19 -0
- package/scripts/hooks/retry-check.sh +32 -0
- package/scripts/hooks/session-cleanup.sh +83 -0
- package/scripts/hooks/session-start.sh +70 -0
- package/scripts/hooks/stop-collect-context.sh +39 -0
- package/scripts/hooks/tool-failure-log.sh +46 -0
- package/scripts/lint.sh +34 -0
- package/scripts/runtime/README.ko.md +60 -0
- package/scripts/runtime/README.md +60 -0
- package/scripts/runtime/adapters/README.ko.md +68 -0
- package/scripts/runtime/adapters/README.md +68 -0
- package/scripts/runtime/adapters/_interface.sh +53 -0
- package/scripts/runtime/adapters/_template.sh +67 -0
- package/scripts/runtime/adapters/generic.sh +78 -0
- package/scripts/runtime/adapters/go.sh +51 -0
- package/scripts/runtime/adapters/jvm.sh +97 -0
- package/scripts/runtime/adapters/node.sh +104 -0
- package/scripts/runtime/adapters/python.sh +116 -0
- package/scripts/runtime/adapters/rust.sh +49 -0
- package/scripts/runtime/detect.sh +52 -0
- package/scripts/scrub-secrets.js +48 -0
- package/scripts/snapshot.sh +45 -0
- package/scripts/test.sh +34 -0
- package/scripts/verify.sh +35 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
cd "$ROOT_DIR" || exit 1
|
|
6
|
+
|
|
7
|
+
TS="$(date +%Y%m%d-%H%M%S)"
|
|
8
|
+
OUT_DIR="docs/smoke-logs/$TS"
|
|
9
|
+
mkdir -p "$OUT_DIR"
|
|
10
|
+
|
|
11
|
+
REPORT_MD="$OUT_DIR/COMMAND_SMOKE_REPORT.md"
|
|
12
|
+
REPORT_CSV="$OUT_DIR/COMMAND_SMOKE_REPORT.csv"
|
|
13
|
+
|
|
14
|
+
cat > "$REPORT_MD" <<MD
|
|
15
|
+
# Claude Command Smoke Report
|
|
16
|
+
|
|
17
|
+
- Generated at: $(date '+%Y-%m-%d %H:%M:%S %Z')
|
|
18
|
+
- Workspace: $ROOT_DIR
|
|
19
|
+
- Runner: claude -p (real Claude Code CLI)
|
|
20
|
+
- Verdict rule: PASS on exit code 0, then downgraded to FAIL if output contains runtime-failure markers ('Error:', 'Failed:', 'not installed on this system', 'Reached max turns')
|
|
21
|
+
|
|
22
|
+
| # | Command | Exit Code | Verdict | Output File |
|
|
23
|
+
|---|---|---:|---|---|
|
|
24
|
+
MD
|
|
25
|
+
|
|
26
|
+
echo "index,command,exit_code,verdict,output_file" > "$REPORT_CSV"
|
|
27
|
+
|
|
28
|
+
# Keep commands short/safe but real.
|
|
29
|
+
declare -a COMMAND_NAMES=(
|
|
30
|
+
"/do"
|
|
31
|
+
"/do-sonnet"
|
|
32
|
+
"/do-opus"
|
|
33
|
+
"/plan"
|
|
34
|
+
"/dplan"
|
|
35
|
+
"/review"
|
|
36
|
+
"/watch"
|
|
37
|
+
"/session-save"
|
|
38
|
+
"/session-load"
|
|
39
|
+
"/compact-phase"
|
|
40
|
+
"/load-context"
|
|
41
|
+
"/learn"
|
|
42
|
+
"/analyze-failures"
|
|
43
|
+
"/llms-txt"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
declare -a PROMPTS=(
|
|
47
|
+
"/do Reply with exactly one word: done"
|
|
48
|
+
"/do-sonnet Reply with exactly one word: done"
|
|
49
|
+
"/do-opus Reply with exactly one word: done"
|
|
50
|
+
"/plan --no-build Smoke test only: output a one-line plan for README wording cleanup."
|
|
51
|
+
"/dplan Smoke test only: output two bullet points for verifying a README update."
|
|
52
|
+
"/review README.md"
|
|
53
|
+
"/watch custom \"echo smoke-watch\""
|
|
54
|
+
"/session-save smoke-test"
|
|
55
|
+
"/session-load --list"
|
|
56
|
+
"/compact-phase planning"
|
|
57
|
+
"/load-context --list"
|
|
58
|
+
"/learn \"Smoke test pattern: keep responses concise\""
|
|
59
|
+
"/analyze-failures 5"
|
|
60
|
+
"/llms-txt nextjs"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
run_one() {
|
|
64
|
+
local idx="$1"
|
|
65
|
+
local command_name="$2"
|
|
66
|
+
local prompt="$3"
|
|
67
|
+
local out_file="$OUT_DIR/$(printf "%02d" "$idx")-${command_name//\//}.out.txt"
|
|
68
|
+
|
|
69
|
+
# shellcheck disable=SC2086
|
|
70
|
+
claude -p "$prompt" \
|
|
71
|
+
--output-format text \
|
|
72
|
+
--max-turns 4 \
|
|
73
|
+
--permission-mode bypassPermissions \
|
|
74
|
+
--allow-dangerously-skip-permissions \
|
|
75
|
+
> "$out_file" 2>&1
|
|
76
|
+
local rc=$?
|
|
77
|
+
|
|
78
|
+
local verdict="FAIL"
|
|
79
|
+
if [ "$rc" -eq 0 ]; then
|
|
80
|
+
verdict="PASS"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Output-based downgrade: some slash commands return exit 0 but still report runtime failure.
|
|
84
|
+
if grep -Eqi '(^Error:|Failed:|not installed on this system|Reached max turns|write was blocked|grant write (permission|access))' "$out_file"; then
|
|
85
|
+
verdict="FAIL"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
printf '| %s | `%s` | %s | %s | `%s` |\n' "$idx" "$command_name" "$rc" "$verdict" "$out_file" >> "$REPORT_MD"
|
|
89
|
+
printf '%s,%s,%s,%s,%s\n' "$idx" "$command_name" "$rc" "$verdict" "$out_file" >> "$REPORT_CSV"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for i in "${!COMMAND_NAMES[@]}"; do
|
|
93
|
+
idx=$((i + 1))
|
|
94
|
+
run_one "$idx" "${COMMAND_NAMES[$i]}" "${PROMPTS[$i]}"
|
|
95
|
+
done
|
|
96
|
+
|
|
97
|
+
# summary block
|
|
98
|
+
pass_count=$(awk -F, 'NR>1 && $4=="PASS" {c++} END {print c+0}' "$REPORT_CSV")
|
|
99
|
+
fail_count=$(awk -F, 'NR>1 && $4=="FAIL" {c++} END {print c+0}' "$REPORT_CSV")
|
|
100
|
+
total_count=$((pass_count + fail_count))
|
|
101
|
+
|
|
102
|
+
cat >> "$REPORT_MD" <<MD
|
|
103
|
+
|
|
104
|
+
## Summary
|
|
105
|
+
|
|
106
|
+
- Total: $total_count
|
|
107
|
+
- PASS: $pass_count
|
|
108
|
+
- FAIL: $fail_count
|
|
109
|
+
|
|
110
|
+
## Notes
|
|
111
|
+
|
|
112
|
+
- This is a minimum smoke run, not behavioral correctness certification.
|
|
113
|
+
- Raw outputs are preserved per command in the same directory.
|
|
114
|
+
MD
|
|
115
|
+
|
|
116
|
+
echo "$OUT_DIR"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# commit.sh - Conventional commit
|
|
3
|
+
set -e
|
|
4
|
+
TYPE=$1; SCOPE=$2; MSG=$3
|
|
5
|
+
case $TYPE in feat|fix|docs|style|refactor|perf|test|chore) ;; *) echo "Invalid type: $TYPE"; exit 1 ;; esac
|
|
6
|
+
[ -z "$SCOPE" ] || [ -z "$MSG" ] && echo "Usage: $0 <type> <scope> <msg>" && exit 1
|
|
7
|
+
git commit -m "${TYPE}(${SCOPE}): ${MSG}"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# create-branch.sh - Deterministic branch creation
|
|
3
|
+
set -e
|
|
4
|
+
TYPE=$1; NAME=$2
|
|
5
|
+
case $TYPE in
|
|
6
|
+
feature|f) PREFIX="feature" ;;
|
|
7
|
+
fix|b) PREFIX="fix" ;;
|
|
8
|
+
hotfix|h) PREFIX="hotfix" ;;
|
|
9
|
+
refactor|r) PREFIX="refactor" ;;
|
|
10
|
+
chore|c) PREFIX="chore" ;;
|
|
11
|
+
*) echo "Use: feature, fix, hotfix, refactor, chore"; exit 1 ;;
|
|
12
|
+
esac
|
|
13
|
+
[ -z "$NAME" ] && echo "Usage: $0 <type> <name>" && exit 1
|
|
14
|
+
git checkout -b "${PREFIX}/$(echo $NAME | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
> **[English Version](README.md)**
|
|
2
|
+
|
|
3
|
+
# Hooks Directory
|
|
4
|
+
|
|
5
|
+
## 목적
|
|
6
|
+
Claude Code의 공식 Hooks 시스템에서 실행되는 로컬 자동화 스크립트입니다. Hook 실행 자체는 quota를 소비하지 않으며, Claude에게 보여지는 출력 메시지만 최소한의 입력 토큰을 소비합니다.
|
|
7
|
+
|
|
8
|
+
## Hook 생명주기
|
|
9
|
+
|
|
10
|
+
```mermaid
|
|
11
|
+
flowchart TB
|
|
12
|
+
%% 스타일 정의 %%
|
|
13
|
+
classDef startend fill:#f9f9f9,stroke:#333,stroke-width:2px;
|
|
14
|
+
classDef script fill:#ffead0,stroke:#e67e22,stroke-width:2px,stroke-dasharray: 5 5;
|
|
15
|
+
classDef process fill:#e1f5fe,stroke:#039be5,stroke-width:2px;
|
|
16
|
+
classDef decision fill:#fff9c4,stroke:#fbc02d,stroke-width:2px;
|
|
17
|
+
classDef error fill:#ffebee,stroke:#ef5350,stroke-width:2px;
|
|
18
|
+
|
|
19
|
+
Start((🚀 세션 시작)):::startend --> SS{{session-start.sh}}:::script
|
|
20
|
+
SS --> Request
|
|
21
|
+
|
|
22
|
+
subgraph WorkLoop["🔄 작업 루프"]
|
|
23
|
+
Request[📝 사용자 요청]:::process --> ToolType{도구 종류?}:::decision
|
|
24
|
+
|
|
25
|
+
%% PreToolUse 분기 %%
|
|
26
|
+
ToolType -->|Bash| CAC{{critical-action-check.sh}}:::script
|
|
27
|
+
ToolType -->|Write/Edit<br/>reviewer| ROC{{readonly-check.sh}}:::script
|
|
28
|
+
ToolType -->|기타| Tool
|
|
29
|
+
|
|
30
|
+
CAC -->|exit 0| Tool[⚙️ 도구 실행]:::process
|
|
31
|
+
CAC -->|exit 2| Block[🚫 차단]:::error
|
|
32
|
+
ROC -->|exit 0| Tool
|
|
33
|
+
ROC -->|exit 2| Block
|
|
34
|
+
|
|
35
|
+
Block --> Request
|
|
36
|
+
|
|
37
|
+
%% PostToolUse %%
|
|
38
|
+
Tool --> IsWrite{Write/Edit?}:::decision
|
|
39
|
+
IsWrite -->|Yes| PEF{{post-edit-format.sh}}:::script
|
|
40
|
+
IsWrite -->|No| Continue
|
|
41
|
+
PEF --> CS{{compact-suggest.sh}}:::script
|
|
42
|
+
CS --> Continue
|
|
43
|
+
|
|
44
|
+
%% Notification %%
|
|
45
|
+
Continue[계속] --> Perm{권한 요청?}:::decision
|
|
46
|
+
Perm -->|Yes| NF{{notification.sh}}:::script
|
|
47
|
+
Perm -->|No| Request
|
|
48
|
+
NF --> Request
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
WorkLoop --> End((🏁 세션 종료)):::startend
|
|
52
|
+
End --> SC{{session-cleanup.sh}}:::script
|
|
53
|
+
|
|
54
|
+
%% Builder 전용 - 별도 플로우 %%
|
|
55
|
+
subgraph BuilderOnly["🔧 Builder Agent Only"]
|
|
56
|
+
AgentDone([에이전트 완료]) --> RC{{retry-check.sh}}:::script
|
|
57
|
+
RC -->|2회+ 실패| Escalate[⚠️ 에스컬레이션]:::error
|
|
58
|
+
RC -->|정상| Done[✅ 완료]
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Hook 스크립트
|
|
63
|
+
|
|
64
|
+
| 스크립트 | 이벤트 | 목적 | 실행 비용 |
|
|
65
|
+
|--------|-------|---------|------------|
|
|
66
|
+
| `critical-action-check.sh` | PreToolUse | 위험한 Bash 명령 차단 | 로컬 (무료), 차단 시 메시지 |
|
|
67
|
+
| `post-edit-format.sh` | PostToolUse | 편집된 파일 자동 포맷 | 로컬 (무료) |
|
|
68
|
+
| `compact-suggest.sh` | PostToolUse | 3단계 컴팩션 경고 (25 권고 / 50 경고 / 75 위험) | 로컬 (무료), 티어당 ~30 토큰 |
|
|
69
|
+
| `notification.sh` | Notification | 권한/입력 대기 시 데스크톱 알림 | 로컬 (무료) |
|
|
70
|
+
| `session-start.sh` | SessionStart | 환경변수 설정 + 예산 알림 + 세션 알림 | 로컬 (무료), 예산 컨텍스트 ~40 입력 토큰 |
|
|
71
|
+
| `session-cleanup.sh` | SessionEnd | 비밀 정보 제거 + 세션 요약 저장 | 로컬 (무료) |
|
|
72
|
+
| `retry-check.sh` | Stop | 연속 2회 실패 시 차단 (builder만) | 로컬 (무료), 에스컬레이션 메시지 |
|
|
73
|
+
| `stop-collect-context.sh` | Stop | 실패 컨텍스트 수집 (선택 사항) | 로컬 (무료) |
|
|
74
|
+
| `readonly-check.sh` | PreToolUse | 읽기 전용 적용 (reviewer) | 로컬 (무료), 차단 시 메시지 |
|
|
75
|
+
| `pre-compact.sh` | PreCompact | 압축 전 상태 저장 | 로컬 (무료) |
|
|
76
|
+
| `tool-failure-log.sh` | PostToolUseFailure | 도구 실패 로깅 | 로컬 (무료) |
|
|
77
|
+
|
|
78
|
+
**비용 설명:** 모든 Hook은 머신에서 로컬로 실행되어 API 호출이 없습니다. Hook이 Claude에게 메시지를 표시할 때만(예: 명령 차단, 컴팩션 제안) 해당 메시지가 입력 토큰을 소비하며, 이러한 메시지는 의도적으로 간결합니다.
|
|
79
|
+
|
|
80
|
+
## 종료 코드
|
|
81
|
+
|
|
82
|
+
| 코드 | 동작 |
|
|
83
|
+
|------|----------|
|
|
84
|
+
| 0 | 정상 계속 |
|
|
85
|
+
| 1 | 오류 (기록됨, 계속) |
|
|
86
|
+
| 2 | 도구 실행 **차단** 및 피드백 |
|
|
87
|
+
|
|
88
|
+
## 입출력
|
|
89
|
+
|
|
90
|
+
Hooks는 stdin을 통해 JSON을 받습니다. 스키마는 이벤트 유형에 따라 다릅니다.
|
|
91
|
+
|
|
92
|
+
**예시 (PreToolUse/Bash):**
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"tool_name": "Bash",
|
|
96
|
+
"tool_input": { "command": "git push --force" }
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**예시 (Stop):**
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"stop_hook_active": true,
|
|
104
|
+
"transcript_path": "/path/to/transcript"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
차단(exit 2) 시 **stderr**로의 출력이 Claude에게 표시됩니다. 참고: exit 2에서는 stdout JSON이 처리되지 않습니다.
|
|
109
|
+
|
|
110
|
+
> **참고:** 정확한 스키마는 공식 Claude Code 문서를 참조하세요: https://code.claude.com/docs/ko/hooks
|
|
111
|
+
|
|
112
|
+
## 새 Hook 추가
|
|
113
|
+
|
|
114
|
+
1. 이 디렉토리에 스크립트 생성
|
|
115
|
+
2. 실행 가능하게 만들기: `chmod +x script.sh`
|
|
116
|
+
3. `settings.json` 또는 에이전트 frontmatter에 추가
|
|
117
|
+
4. 다양한 입력으로 테스트
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
> **[한국어 버전](README.ko.md)**
|
|
2
|
+
|
|
3
|
+
# Hooks Directory
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
Local automation scripts executed by Claude Code's official Hooks system. Hook execution itself consumes zero quota—only their output messages (when shown to Claude) consume minimal input tokens.
|
|
7
|
+
|
|
8
|
+
## Hook Lifecycle
|
|
9
|
+
|
|
10
|
+
```mermaid
|
|
11
|
+
flowchart TB
|
|
12
|
+
%% Style definitions %%
|
|
13
|
+
classDef startend fill:#f9f9f9,stroke:#333,stroke-width:2px;
|
|
14
|
+
classDef script fill:#ffead0,stroke:#e67e22,stroke-width:2px,stroke-dasharray: 5 5;
|
|
15
|
+
classDef process fill:#e1f5fe,stroke:#039be5,stroke-width:2px;
|
|
16
|
+
classDef decision fill:#fff9c4,stroke:#fbc02d,stroke-width:2px;
|
|
17
|
+
classDef error fill:#ffebee,stroke:#ef5350,stroke-width:2px;
|
|
18
|
+
|
|
19
|
+
Start((🚀 Session Start)):::startend --> SS{{session-start.sh}}:::script
|
|
20
|
+
SS --> Request
|
|
21
|
+
|
|
22
|
+
subgraph WorkLoop["🔄 Work Loop"]
|
|
23
|
+
Request[📝 User Request]:::process --> ToolType{Tool Type?}:::decision
|
|
24
|
+
|
|
25
|
+
%% PreToolUse branches %%
|
|
26
|
+
ToolType -->|Bash| CAC{{critical-action-check.sh}}:::script
|
|
27
|
+
ToolType -->|Write/Edit<br/>reviewer| ROC{{readonly-check.sh}}:::script
|
|
28
|
+
ToolType -->|Other| Tool
|
|
29
|
+
|
|
30
|
+
CAC -->|exit 0| Tool[⚙️ Tool Execution]:::process
|
|
31
|
+
CAC -->|exit 2| Block[🚫 Blocked]:::error
|
|
32
|
+
ROC -->|exit 0| Tool
|
|
33
|
+
ROC -->|exit 2| Block
|
|
34
|
+
|
|
35
|
+
Block --> Request
|
|
36
|
+
|
|
37
|
+
%% PostToolUse %%
|
|
38
|
+
Tool --> IsWrite{Write/Edit?}:::decision
|
|
39
|
+
IsWrite -->|Yes| PEF{{post-edit-format.sh}}:::script
|
|
40
|
+
IsWrite -->|No| Continue
|
|
41
|
+
PEF --> CS{{compact-suggest.sh}}:::script
|
|
42
|
+
CS --> Continue
|
|
43
|
+
|
|
44
|
+
%% Notification %%
|
|
45
|
+
Continue[Continue] --> Perm{Permission?}:::decision
|
|
46
|
+
Perm -->|Yes| NF{{notification.sh}}:::script
|
|
47
|
+
Perm -->|No| Request
|
|
48
|
+
NF --> Request
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
WorkLoop --> End((🏁 Session End)):::startend
|
|
52
|
+
End --> SC{{session-cleanup.sh}}:::script
|
|
53
|
+
|
|
54
|
+
%% Builder only - separate flow %%
|
|
55
|
+
subgraph BuilderOnly["🔧 Builder Agent Only"]
|
|
56
|
+
AgentDone([Agent Complete]) --> RC{{retry-check.sh}}:::script
|
|
57
|
+
RC -->|2+ failures| Escalate[⚠️ Escalate]:::error
|
|
58
|
+
RC -->|OK| Done[✅ Done]
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Hook Scripts
|
|
63
|
+
|
|
64
|
+
| Script | Event | Purpose | Execution Cost |
|
|
65
|
+
|--------|-------|---------|----------------|
|
|
66
|
+
| `critical-action-check.sh` | PreToolUse | Block dangerous Bash commands | Local (zero), blocking message if triggered |
|
|
67
|
+
| `post-edit-format.sh` | PostToolUse | Auto-format edited files | Local (zero) |
|
|
68
|
+
| `compact-suggest.sh` | PostToolUse | 3-tier compact warnings (25 advisory / 50 warning / 75 critical) | Local (zero), ~30 tokens per tier |
|
|
69
|
+
| `notification.sh` | Notification | Desktop alert on permission/idle | Local (zero) |
|
|
70
|
+
| `session-start.sh` | SessionStart | Env setup + budget reminder + session notify | Local (zero), ~40 input tokens for budget context |
|
|
71
|
+
| `session-cleanup.sh` | SessionEnd | Scrub secrets + save session summary | Local (zero) |
|
|
72
|
+
| `retry-check.sh` | Stop | Enforce 2-retry cap (builder only) | Local (zero), escalation message if triggered |
|
|
73
|
+
| `stop-collect-context.sh` | Stop | Collect failure contexts (optional) | Local (zero) |
|
|
74
|
+
| `readonly-check.sh` | PreToolUse | Enforce read-only (reviewer) | Local (zero), blocking message if triggered |
|
|
75
|
+
| `pre-compact.sh` | PreCompact | Save state before compaction | Local (zero) |
|
|
76
|
+
| `tool-failure-log.sh` | PostToolUseFailure | Log failures for debugging | Local (zero) |
|
|
77
|
+
|
|
78
|
+
**Cost Explanation:** All hooks run locally on your machine without API calls. Only when a hook displays a message to Claude (e.g., blocking a command, suggesting compaction) does that message consume input tokens—and these messages are intentionally brief.
|
|
79
|
+
|
|
80
|
+
## Exit Codes
|
|
81
|
+
|
|
82
|
+
| Code | Behavior |
|
|
83
|
+
|------|----------|
|
|
84
|
+
| 0 | Continue normally |
|
|
85
|
+
| 1 | Error (logged, continues) |
|
|
86
|
+
| 2 | **Block** tool execution with feedback |
|
|
87
|
+
|
|
88
|
+
## Input/Output
|
|
89
|
+
|
|
90
|
+
Hooks receive JSON via stdin. Schema varies by event type.
|
|
91
|
+
|
|
92
|
+
**Example (PreToolUse/Bash):**
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"tool_name": "Bash",
|
|
96
|
+
"tool_input": { "command": "git push --force" }
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Example (Stop):**
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"stop_hook_active": true,
|
|
104
|
+
"transcript_path": "/path/to/transcript"
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Output to **stderr** is shown to Claude when blocking (exit 2). Note: stdout JSON is NOT processed for exit code 2.
|
|
109
|
+
|
|
110
|
+
> **Note:** For exact schemas, see official Claude Code documentation: https://code.claude.com/docs/hooks
|
|
111
|
+
|
|
112
|
+
## Adding New Hooks
|
|
113
|
+
|
|
114
|
+
1. Create script in this directory
|
|
115
|
+
2. Make executable: `chmod +x script.sh`
|
|
116
|
+
3. Add to `settings.json` or agent frontmatter
|
|
117
|
+
4. Test with various inputs
|
|
118
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# compact-suggest.sh - PostToolUse Hook (After Edit/Write completion)
|
|
3
|
+
# 3-tier progressive warnings for context growth management
|
|
4
|
+
# Tier 1: 25 (advisory) | Tier 2: 50 (warning) | Tier 3: 75 (critical)
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "default"')
|
|
9
|
+
|
|
10
|
+
COUNTER_FILE="/tmp/claude-tool-count-$SESSION_ID"
|
|
11
|
+
|
|
12
|
+
# Increment counter
|
|
13
|
+
count=$(($(cat "$COUNTER_FILE" 2>/dev/null || echo 0) + 1))
|
|
14
|
+
echo "$count" > "$COUNTER_FILE"
|
|
15
|
+
|
|
16
|
+
# Tier 1: Advisory (25 tool calls)
|
|
17
|
+
if [ "$count" -eq 25 ]; then
|
|
18
|
+
cat <<EOF
|
|
19
|
+
{
|
|
20
|
+
"hookSpecificOutput": {
|
|
21
|
+
"hookEventName": "PostToolUse",
|
|
22
|
+
"additionalContext": "[COMPACT-ADVISORY] 25 tool calls. Context growing — consider /compact-phase at next logical break."
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
EOF
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Tier 2: Warning (50 tool calls)
|
|
29
|
+
if [ "$count" -eq 50 ]; then
|
|
30
|
+
cat <<EOF
|
|
31
|
+
{
|
|
32
|
+
"hookSpecificOutput": {
|
|
33
|
+
"hookEventName": "PostToolUse",
|
|
34
|
+
"additionalContext": "[COMPACT-WARNING] 50 tool calls. Quota burn rate increasing — run /compact before next task."
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
EOF
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Tier 3: Critical (75 tool calls — approaching auto-compact at 75% context)
|
|
41
|
+
if [ "$count" -eq 75 ]; then
|
|
42
|
+
cat <<EOF
|
|
43
|
+
{
|
|
44
|
+
"hookSpecificOutput": {
|
|
45
|
+
"hookEventName": "PostToolUse",
|
|
46
|
+
"additionalContext": "[COMPACT-CRITICAL] 75 tool calls. High context — /compact NOW or /session-save + new session."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
EOF
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# critical-action-check.sh - PreToolUse Hook
|
|
3
|
+
# Block dangerous commands (0 tokens, ~50 tokens on block)
|
|
4
|
+
# Hardened Hook + Multi-Runtime
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
|
|
10
|
+
|
|
11
|
+
# If not a Bash tool or no command, skip
|
|
12
|
+
[ -z "$COMMAND" ] && exit 0
|
|
13
|
+
|
|
14
|
+
# 1. Direct Dangerous Commands (CRITICAL)
|
|
15
|
+
DIRECT_PATTERNS=(
|
|
16
|
+
'rm -rf /'
|
|
17
|
+
'rm -rf ~'
|
|
18
|
+
'rm -rf \.'
|
|
19
|
+
'git push.*--force'
|
|
20
|
+
'git reset --hard'
|
|
21
|
+
'DROP TABLE'
|
|
22
|
+
'TRUNCATE'
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
for pattern in "${DIRECT_PATTERNS[@]}"; do
|
|
26
|
+
if echo "$COMMAND" | grep -iE "$pattern" > /dev/null 2>&1; then
|
|
27
|
+
echo "CRITICAL: Blocked dangerous command: $COMMAND" >&2
|
|
28
|
+
exit 2
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
# Block DELETE FROM without WHERE (Separate handling as ERE does not support negative lookahead)
|
|
33
|
+
if echo "$COMMAND" | grep -iE 'DELETE FROM' > /dev/null 2>&1; then
|
|
34
|
+
if ! echo "$COMMAND" | grep -iE 'WHERE' > /dev/null 2>&1; then
|
|
35
|
+
echo "CRITICAL: Blocked DELETE FROM without WHERE clause: $COMMAND" >&2
|
|
36
|
+
exit 2
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# 2. Indirect Dangerous Scripts (WARNING -> BLOCK)
|
|
41
|
+
# Multi-runtime support
|
|
42
|
+
INDIRECT_PATTERNS=(
|
|
43
|
+
'npm run.*\b(clean|reset|nuke|purge)\b'
|
|
44
|
+
'yarn.*\b(clean|reset|nuke|purge)\b'
|
|
45
|
+
'pnpm.*\b(clean|reset|nuke|purge)\b'
|
|
46
|
+
'./gradlew.*\b(clean)\b'
|
|
47
|
+
'gradle.*\b(clean)\b'
|
|
48
|
+
'mvn.*\b(clean)\b'
|
|
49
|
+
'cargo.*\b(clean)\b'
|
|
50
|
+
'go.*\b(clean)\b'
|
|
51
|
+
'\b(db:reset|db:drop|migrate:reset)\b'
|
|
52
|
+
'\b(deploy:prod|deploy:production)\b'
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
for pattern in "${INDIRECT_PATTERNS[@]}"; do
|
|
56
|
+
if echo "$COMMAND" | grep -iE "$pattern" > /dev/null 2>&1; then
|
|
57
|
+
echo "WARNING: Blocked indirect dangerous script: $COMMAND" >&2
|
|
58
|
+
exit 2
|
|
59
|
+
fi
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
# 3. Detect Git Conflict
|
|
63
|
+
if echo "$COMMAND" | grep -E '(CONFLICT|<<<<<<<|>>>>>>>)' > /dev/null 2>&1; then
|
|
64
|
+
echo "CONFLICT: Git conflict detected. Manual resolution required." >&2
|
|
65
|
+
exit 2
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
exit 0
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# notification.sh - Notification Hook
|
|
3
|
+
# Desktop notification for permission prompts / idle state (0 tokens)
|
|
4
|
+
# Official Guide: https://code.claude.com/docs/en/hooks-guide
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
TYPE=$(echo "$INPUT" | jq -r '.notification_type // empty')
|
|
9
|
+
MESSAGE=$(echo "$INPUT" | jq -r '.message // "Claude Code Notification"')
|
|
10
|
+
|
|
11
|
+
# Notification function (OS-specific)
|
|
12
|
+
send_notification() {
|
|
13
|
+
local title="$1"
|
|
14
|
+
local body="$2"
|
|
15
|
+
|
|
16
|
+
# macOS
|
|
17
|
+
if command -v osascript &>/dev/null; then
|
|
18
|
+
osascript -e "display notification \"$body\" with title \"$title\"" 2>/dev/null || true
|
|
19
|
+
return
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Linux (notify-send)
|
|
23
|
+
if command -v notify-send &>/dev/null; then
|
|
24
|
+
notify-send "$title" "$body" 2>/dev/null || true
|
|
25
|
+
return
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Windows (PowerShell)
|
|
29
|
+
if command -v powershell.exe &>/dev/null; then
|
|
30
|
+
powershell.exe -Command "[System.Windows.Forms.MessageBox]::Show('$body', '$title')" 2>/dev/null || true
|
|
31
|
+
return
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
case "$TYPE" in
|
|
36
|
+
permission_prompt)
|
|
37
|
+
send_notification "Claude Code" "🔐 Permission required"
|
|
38
|
+
;;
|
|
39
|
+
idle_prompt)
|
|
40
|
+
send_notification "Claude Code" "⏳ Waiting for input"
|
|
41
|
+
;;
|
|
42
|
+
*)
|
|
43
|
+
# Ignore other notifications (to save resources)
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
exit 0
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# post-edit-format.sh - PostToolUse Hook
|
|
3
|
+
# Auto-formatting after file edits (0 tokens)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_response.filePath // empty')
|
|
10
|
+
|
|
11
|
+
# Skip if file path is missing or file does not exist
|
|
12
|
+
[ -z "$FILE_PATH" ] && exit 0
|
|
13
|
+
[ ! -f "$FILE_PATH" ] && exit 0
|
|
14
|
+
|
|
15
|
+
# Select formatter by extension
|
|
16
|
+
case "$FILE_PATH" in
|
|
17
|
+
*.ts|*.tsx|*.js|*.jsx|*.json|*.css|*.md)
|
|
18
|
+
if command -v prettier &>/dev/null; then
|
|
19
|
+
prettier --write "$FILE_PATH" 2>/dev/null || true
|
|
20
|
+
fi
|
|
21
|
+
;;
|
|
22
|
+
*.py)
|
|
23
|
+
if command -v black &>/dev/null; then
|
|
24
|
+
black --quiet "$FILE_PATH" 2>/dev/null || true
|
|
25
|
+
fi
|
|
26
|
+
;;
|
|
27
|
+
*.go)
|
|
28
|
+
if command -v gofmt &>/dev/null; then
|
|
29
|
+
gofmt -w "$FILE_PATH" 2>/dev/null || true
|
|
30
|
+
fi
|
|
31
|
+
;;
|
|
32
|
+
*.rs)
|
|
33
|
+
if command -v rustfmt &>/dev/null; then
|
|
34
|
+
rustfmt "$FILE_PATH" 2>/dev/null || true
|
|
35
|
+
fi
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
|
|
39
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# pre-compact.sh - PreCompact Hook
|
|
3
|
+
# Automatically save state before context compaction (0 tokens)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# Check jq dependency
|
|
11
|
+
if ! command -v jq &> /dev/null; then
|
|
12
|
+
echo "Error: jq is required but not installed." >&2
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
SESSION_DIR="$HOME/.claude/sessions"
|
|
17
|
+
mkdir -p "$SESSION_DIR"
|
|
18
|
+
|
|
19
|
+
# Compaction trigger type (manual/auto)
|
|
20
|
+
TRIGGER=$(echo "$INPUT" | jq -r '.trigger // "unknown"')
|
|
21
|
+
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
|
22
|
+
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
|
23
|
+
|
|
24
|
+
# Create state file
|
|
25
|
+
STATE_FILE="$SESSION_DIR/${TIMESTAMP}-pre-compact.md"
|
|
26
|
+
|
|
27
|
+
cat > "$STATE_FILE" <<EOF
|
|
28
|
+
---
|
|
29
|
+
type: pre-compact
|
|
30
|
+
trigger: $TRIGGER
|
|
31
|
+
session_id: $SESSION_ID
|
|
32
|
+
timestamp: $(date +"%Y-%m-%d %H:%M:%S")
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Pre-Compact State
|
|
36
|
+
|
|
37
|
+
## Trigger
|
|
38
|
+
- Type: $TRIGGER
|
|
39
|
+
- Time: $(date +"%H:%M:%S")
|
|
40
|
+
|
|
41
|
+
## Working Directory
|
|
42
|
+
$(pwd)
|
|
43
|
+
|
|
44
|
+
## Git Status
|
|
45
|
+
$(git status --short 2>/dev/null || echo "Not a git repository")
|
|
46
|
+
|
|
47
|
+
## Recent Modified Files
|
|
48
|
+
$(find . -type f \( -name "*.md" -o -name "*.ts" -o -name "*.js" -o -name "*.sh" -o -name "*.json" \) -mmin -30 2>/dev/null | head -10 || echo "No recent files")
|
|
49
|
+
|
|
50
|
+
## Context Hint
|
|
51
|
+
[Claude: Refer to this file to resume work after compaction]
|
|
52
|
+
EOF
|
|
53
|
+
|
|
54
|
+
echo "[PreCompact] State saved: $STATE_FILE" >&2
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# readonly-check.sh - PreToolUse Hook (For Reviewer Subagent)
|
|
3
|
+
# Block Write/Edit operations (0 tokens, ~50 tokens on block)
|
|
4
|
+
# Hardened Hook
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
|
|
10
|
+
|
|
11
|
+
# Block writing tools
|
|
12
|
+
case "$TOOL_NAME" in
|
|
13
|
+
Write|Edit|NotebookEdit)
|
|
14
|
+
echo "READONLY: Reviewer agent cannot modify files. Read-only access only." >&2
|
|
15
|
+
exit 2
|
|
16
|
+
;;
|
|
17
|
+
esac
|
|
18
|
+
|
|
19
|
+
exit 0
|