oh-my-customcode 0.145.0 → 0.146.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/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -546,6 +546,16 @@
|
|
|
546
546
|
],
|
|
547
547
|
"description": "Auto-extract failure patterns from session outcomes (advisory, exit 0)"
|
|
548
548
|
},
|
|
549
|
+
{
|
|
550
|
+
"matcher": "*",
|
|
551
|
+
"hooks": [
|
|
552
|
+
{
|
|
553
|
+
"type": "command",
|
|
554
|
+
"command": "bash .claude/hooks/scripts/session-reflection.sh"
|
|
555
|
+
}
|
|
556
|
+
],
|
|
557
|
+
"description": "Transcript-based self-reflection: detect R007/R008 violations and log to .claude/outputs/reflections/ (Phase 1 MVP, advisory, exit 0)"
|
|
558
|
+
},
|
|
549
559
|
{
|
|
550
560
|
"matcher": "*",
|
|
551
561
|
"hooks": [
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# session-reflection.sh — Stop hook: transcript-based self-reflection for R007/R008 violations
|
|
3
|
+
# Phase 1 MVP: detects header absence (R007) and tool prefix absence (R008)
|
|
4
|
+
# Advisory-only: always exits 0, never blocks session end
|
|
5
|
+
#
|
|
6
|
+
# 환경변수 override (테스트/디버깅용):
|
|
7
|
+
# OMCUSTOM_SESSION_REFLECTION=off — 분석 완전 비활성화
|
|
8
|
+
# OMCUSTOM_TRANSCRIPT_BASE — transcript 디렉토리 경로 override
|
|
9
|
+
# OMCUSTOM_PROJECT_ROOT — 프로젝트 루트 override (.claude/outputs/reflections 기준)
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
# ── Stop hook 프로토콜: stdin을 먼저 읽음 ──
|
|
14
|
+
input=$(cat)
|
|
15
|
+
|
|
16
|
+
# ── Opt-out 체크 ──
|
|
17
|
+
if [ "${OMCUSTOM_SESSION_REFLECTION:-}" = "off" ]; then
|
|
18
|
+
echo "$input"
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# ── jq 의존성 체크 ──
|
|
23
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
24
|
+
echo "$input"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# ── session_id 추출 ──
|
|
29
|
+
session_id=$(echo "$input" | jq -r '.session_id // empty' 2>/dev/null)
|
|
30
|
+
if [ -z "$session_id" ]; then
|
|
31
|
+
echo "$input"
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# ── 경로 결정 (환경변수 override 지원) ──
|
|
36
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
37
|
+
|
|
38
|
+
# transcript 기본 경로 (OMCUSTOM_TRANSCRIPT_BASE 로 override 가능)
|
|
39
|
+
TRANSCRIPT_BASE="${OMCUSTOM_TRANSCRIPT_BASE:-${HOME}/.claude/projects/-Users-sangyi-workspace-projects-oh-my-customcode}"
|
|
40
|
+
TRANSCRIPT_PATH="${TRANSCRIPT_BASE}/${session_id}.jsonl"
|
|
41
|
+
|
|
42
|
+
if [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
43
|
+
echo "$input"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# 프로젝트 루트 (OMCUSTOM_PROJECT_ROOT 로 override 가능)
|
|
48
|
+
PROJECT_ROOT="${OMCUSTOM_PROJECT_ROOT:-$(cd "${SCRIPT_DIR}/../../.." && pwd)}"
|
|
49
|
+
|
|
50
|
+
# ── 백그라운드 분석 스크립트를 임시 파일로 생성 ──
|
|
51
|
+
# nohup bash -c "..." 또는 heredoc 방식은 글로브 확장/shell escape/stdin 충돌 문제 발생.
|
|
52
|
+
# 임시 파일 방식은 이 문제를 완전히 회피한다.
|
|
53
|
+
WORKER_SCRIPT="/tmp/.claude-reflection-worker-${PPID}-$$.sh"
|
|
54
|
+
|
|
55
|
+
cat > "$WORKER_SCRIPT" <<'WORKER_EOF'
|
|
56
|
+
#!/usr/bin/env bash
|
|
57
|
+
# Background worker: transcript analysis for R007/R008 violations
|
|
58
|
+
|
|
59
|
+
set -euo pipefail
|
|
60
|
+
|
|
61
|
+
TRANSCRIPT_PATH="$1"
|
|
62
|
+
PROJECT_ROOT="$2"
|
|
63
|
+
SESSION_ID="$3"
|
|
64
|
+
SCRIPT_DIR="$4"
|
|
65
|
+
|
|
66
|
+
# 출력 디렉토리 준비
|
|
67
|
+
OUTPUT_DIR="${PROJECT_ROOT}/.claude/outputs/reflections"
|
|
68
|
+
mkdir -p "${OUTPUT_DIR}"
|
|
69
|
+
|
|
70
|
+
LOG_FILE="${OUTPUT_DIR}/$(date +%Y-%m-%d).md"
|
|
71
|
+
ISO8601="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
72
|
+
|
|
73
|
+
# ── transcript 파싱 ──
|
|
74
|
+
r007_violations=0
|
|
75
|
+
r008_violations=0
|
|
76
|
+
total_turns=0
|
|
77
|
+
sample_count=0
|
|
78
|
+
sample_lines=""
|
|
79
|
+
|
|
80
|
+
while IFS= read -r line; do
|
|
81
|
+
role=$(echo "$line" | jq -r '.role // empty' 2>/dev/null) || continue
|
|
82
|
+
[ "$role" = "assistant" ] || continue
|
|
83
|
+
|
|
84
|
+
total_turns=$((total_turns + 1))
|
|
85
|
+
turn_idx=$total_turns
|
|
86
|
+
|
|
87
|
+
# content 배열 파싱
|
|
88
|
+
content_raw=$(echo "$line" | jq -c '.content // []' 2>/dev/null) || continue
|
|
89
|
+
|
|
90
|
+
# ── R007: 첫 번째 text 블록의 첫 줄 체크 ──
|
|
91
|
+
first_text=$(echo "$content_raw" | jq -r '[.[] | select(.type == "text")][0].text // empty' 2>/dev/null) || true
|
|
92
|
+
if [ -n "$first_text" ]; then
|
|
93
|
+
first_line=$(printf '%s' "$first_text" | head -1)
|
|
94
|
+
# R007 패턴: '┌─ Agent:' 또는 '[anything]' 단축 형태
|
|
95
|
+
if ! printf '%s' "$first_line" | grep -qE '(^┌─ Agent:|^\[.+\])'; then
|
|
96
|
+
r007_violations=$((r007_violations + 1))
|
|
97
|
+
if [ $sample_count -lt 3 ]; then
|
|
98
|
+
# 120자 truncate (secret-filter.sh는 PostToolUse용이라 여기서는 단순 truncate)
|
|
99
|
+
safe_text=$(printf '%s' "$first_line" | head -c 120)
|
|
100
|
+
sample_lines="${sample_lines}
|
|
101
|
+
- [R007 turn ${turn_idx}]: ${safe_text}"
|
|
102
|
+
sample_count=$((sample_count + 1))
|
|
103
|
+
fi
|
|
104
|
+
fi
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# ── R008: tool_use 블록 직전 text에 prefix 체크 ──
|
|
108
|
+
content_length=$(echo "$content_raw" | jq 'length' 2>/dev/null) || continue
|
|
109
|
+
|
|
110
|
+
i=0
|
|
111
|
+
while [ $i -lt "$content_length" ]; do
|
|
112
|
+
block_type=$(echo "$content_raw" | jq -r ".[$i].type // empty" 2>/dev/null) || { i=$((i+1)); continue; }
|
|
113
|
+
|
|
114
|
+
if [ "$block_type" = "tool_use" ]; then
|
|
115
|
+
tool_name=$(echo "$content_raw" | jq -r ".[$i].name // empty" 2>/dev/null) || true
|
|
116
|
+
|
|
117
|
+
# 직전 블록이 text이고 R008 prefix를 포함하는지 체크
|
|
118
|
+
has_prefix=false
|
|
119
|
+
if [ $i -gt 0 ]; then
|
|
120
|
+
prev_type=$(echo "$content_raw" | jq -r ".[$(( i - 1 ))].type // empty" 2>/dev/null) || true
|
|
121
|
+
if [ "$prev_type" = "text" ]; then
|
|
122
|
+
prev_text=$(echo "$content_raw" | jq -r ".[$(( i - 1 ))].text // empty" 2>/dev/null) || true
|
|
123
|
+
# R008 패턴: '[agent-name][model] → Tool:' 또는 '→ Target:'
|
|
124
|
+
if printf '%s' "$prev_text" | grep -qE '\[.+\]\[.+\] ?(→|->|—>) ?(Tool|Target):'; then
|
|
125
|
+
has_prefix=true
|
|
126
|
+
fi
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ "$has_prefix" = "false" ]; then
|
|
131
|
+
r008_violations=$((r008_violations + 1))
|
|
132
|
+
if [ $sample_count -lt 3 ]; then
|
|
133
|
+
sample_lines="${sample_lines}
|
|
134
|
+
- [R008 turn ${turn_idx}]: ${tool_name}, missing prefix"
|
|
135
|
+
sample_count=$((sample_count + 1))
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
i=$((i+1))
|
|
141
|
+
done
|
|
142
|
+
|
|
143
|
+
done < "$TRANSCRIPT_PATH"
|
|
144
|
+
|
|
145
|
+
# ── 로그 작성 ──
|
|
146
|
+
{
|
|
147
|
+
echo ""
|
|
148
|
+
echo "## Session ${SESSION_ID} — ${ISO8601}"
|
|
149
|
+
echo ""
|
|
150
|
+
echo "- **R007 violations**: ${r007_violations}"
|
|
151
|
+
echo "- **R008 violations**: ${r008_violations}"
|
|
152
|
+
echo "- Total assistant turns analyzed: ${total_turns}"
|
|
153
|
+
if [ $sample_count -gt 0 ]; then
|
|
154
|
+
echo ""
|
|
155
|
+
echo "### Sample violations (최대 3개)"
|
|
156
|
+
printf '%s\n' "${sample_lines}"
|
|
157
|
+
fi
|
|
158
|
+
} >> "${LOG_FILE}"
|
|
159
|
+
|
|
160
|
+
echo "[session-reflection] Analysis complete: R007=${r007_violations} R008=${r008_violations} turns=${total_turns}" >&2
|
|
161
|
+
WORKER_EOF
|
|
162
|
+
|
|
163
|
+
chmod +x "$WORKER_SCRIPT"
|
|
164
|
+
|
|
165
|
+
# ── 백그라운드로 실행 (Stop hook 시간 예산 <3s 준수) ──
|
|
166
|
+
# setsid로 부모 종료 후에도 실행 지속; 완료 후 임시 파일 자정리
|
|
167
|
+
WORKER_ERR_LOG="/tmp/.claude-reflection-err-${PPID}.log"
|
|
168
|
+
|
|
169
|
+
(
|
|
170
|
+
bash "$WORKER_SCRIPT" \
|
|
171
|
+
"$TRANSCRIPT_PATH" \
|
|
172
|
+
"$PROJECT_ROOT" \
|
|
173
|
+
"$session_id" \
|
|
174
|
+
"$SCRIPT_DIR" \
|
|
175
|
+
2>>"$WORKER_ERR_LOG"
|
|
176
|
+
rm -f "$WORKER_SCRIPT"
|
|
177
|
+
) &
|
|
178
|
+
disown $! 2>/dev/null || true
|
|
179
|
+
|
|
180
|
+
# ── 즉시 stdin pass-through 후 exit 0 (Stop hook 체인 유지) ──
|
|
181
|
+
echo "$input"
|
|
182
|
+
exit 0
|
package/templates/manifest.json
CHANGED