oh-my-customcode 1.1.54 → 1.1.56
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 +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +19 -19
- package/templates/.claude/hooks/scripts/agent-start-recorder.sh +5 -5
- package/templates/.claude/hooks/scripts/agent-teams-advisor.sh +4 -4
- package/templates/.claude/hooks/scripts/audit-log.sh +6 -6
- package/templates/.claude/hooks/scripts/auto-continue-guard.sh +1 -1
- package/templates/.claude/hooks/scripts/auto-dev-token-summary.sh +6 -6
- package/templates/.claude/hooks/scripts/auto-dev-token-tracker.sh +6 -6
- package/templates/.claude/hooks/scripts/content-hash-validator.sh +4 -4
- package/templates/.claude/hooks/scripts/context-budget-advisor.sh +3 -3
- package/templates/.claude/hooks/scripts/cost-cap-advisor.sh +6 -6
- package/templates/.claude/hooks/scripts/cwd-change-detector.sh +3 -3
- package/templates/.claude/hooks/scripts/destructive-git-guard.sh +2 -2
- package/templates/.claude/hooks/scripts/eval-core-batch-save.sh +2 -2
- package/templates/.claude/hooks/scripts/feedback-collector.sh +7 -7
- package/templates/.claude/hooks/scripts/file-change-validator.sh +4 -4
- package/templates/.claude/hooks/scripts/git-delegation-guard.sh +3 -3
- package/templates/.claude/hooks/scripts/model-escalation-advisor.sh +4 -4
- package/templates/.claude/hooks/scripts/omcustom-auto-update.sh +6 -6
- package/templates/.claude/hooks/scripts/playwright-compress.sh +4 -4
- package/templates/.claude/hooks/scripts/plugin-cache-check.sh +2 -2
- package/templates/.claude/hooks/scripts/r007-r008-drift-advisor.sh +26 -3
- package/templates/.claude/hooks/scripts/rtk-intercept.sh +9 -9
- package/templates/.claude/hooks/scripts/rule-deletion-guard.sh +5 -5
- package/templates/.claude/hooks/scripts/schema-validator.sh +10 -10
- package/templates/.claude/hooks/scripts/secret-filter.sh +4 -4
- package/templates/.claude/hooks/scripts/session-autofix-prompt.sh +3 -3
- package/templates/.claude/hooks/scripts/session-autofix.sh +1 -1
- package/templates/.claude/hooks/scripts/session-env-check.sh +1 -1
- package/templates/.claude/hooks/scripts/session-reflection.sh +15 -15
- package/templates/.claude/hooks/scripts/skill-extractor-analyzer.sh +2 -2
- package/templates/.claude/hooks/scripts/stale-todo-scanner.sh +1 -1
- package/templates/.claude/hooks/scripts/stall-detection-advisor.sh +11 -11
- package/templates/.claude/hooks/scripts/stop-console-audit.sh +1 -1
- package/templates/.claude/hooks/scripts/stuck-detector.sh +81 -25
- package/templates/.claude/hooks/scripts/subagent-failure-advisor.sh +36 -0
- package/templates/.claude/hooks/scripts/task-outcome-recorder.sh +8 -8
- package/templates/.claude/hooks/scripts/task-state-precompact.sh +1 -1
- package/templates/.claude/settings.json +19 -19
- package/templates/manifest.json +1 -1
|
@@ -12,15 +12,15 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
12
12
|
input=$(cat)
|
|
13
13
|
|
|
14
14
|
# Extract current task info
|
|
15
|
-
agent_type=$(
|
|
16
|
-
current_model=$(
|
|
15
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.tool_input.subagent_type // "unknown"')
|
|
16
|
+
current_model=$(printf '%s\n' "$input" | jq -r '.tool_input.model // "inherit"')
|
|
17
17
|
|
|
18
18
|
# Session-scoped outcome log
|
|
19
19
|
OUTCOME_FILE="/tmp/.claude-task-outcomes-${PPID}"
|
|
20
20
|
|
|
21
21
|
# Skip if no history
|
|
22
22
|
if [ ! -f "$OUTCOME_FILE" ]; then
|
|
23
|
-
|
|
23
|
+
printf '%s\n' "$input"
|
|
24
24
|
exit 0
|
|
25
25
|
fi
|
|
26
26
|
|
|
@@ -107,5 +107,5 @@ if [ "$current_model" != "haiku" ] && [ "$current_model" != "inherit" ] && [ "$c
|
|
|
107
107
|
fi
|
|
108
108
|
|
|
109
109
|
# Pass through
|
|
110
|
-
|
|
110
|
+
printf '%s\n' "$input"
|
|
111
111
|
exit 0
|
|
@@ -12,13 +12,13 @@ input=$(cat)
|
|
|
12
12
|
|
|
13
13
|
# Skip if explicitly disabled
|
|
14
14
|
if [ "${OMCUSTOM_SKIP_AUTO_UPDATE:-}" = "true" ]; then
|
|
15
|
-
|
|
15
|
+
printf '%s\n' "$input"
|
|
16
16
|
exit 0
|
|
17
17
|
fi
|
|
18
18
|
|
|
19
19
|
# Skip if /dev/tty not available (CI, Docker, non-interactive)
|
|
20
20
|
if ! [ -c /dev/tty ] 2>/dev/null; then
|
|
21
|
-
|
|
21
|
+
printf '%s\n' "$input"
|
|
22
22
|
exit 0
|
|
23
23
|
fi
|
|
24
24
|
|
|
@@ -53,7 +53,7 @@ fi
|
|
|
53
53
|
|
|
54
54
|
# Cannot determine current version — skip
|
|
55
55
|
if [ -z "$CURRENT_VERSION" ]; then
|
|
56
|
-
|
|
56
|
+
printf '%s\n' "$input"
|
|
57
57
|
exit 0
|
|
58
58
|
fi
|
|
59
59
|
|
|
@@ -101,14 +101,14 @@ fi
|
|
|
101
101
|
|
|
102
102
|
# Could not determine latest version — skip
|
|
103
103
|
if [ -z "$LATEST_VERSION" ]; then
|
|
104
|
-
|
|
104
|
+
printf '%s\n' "$input"
|
|
105
105
|
exit 0
|
|
106
106
|
fi
|
|
107
107
|
|
|
108
108
|
# --- Step 3: Compare versions ---
|
|
109
109
|
if ! version_lt "$CURRENT_VERSION" "$LATEST_VERSION"; then
|
|
110
110
|
# Already up to date
|
|
111
|
-
|
|
111
|
+
printf '%s\n' "$input"
|
|
112
112
|
exit 0
|
|
113
113
|
fi
|
|
114
114
|
|
|
@@ -166,5 +166,5 @@ fi
|
|
|
166
166
|
echo "------------------------------------" >&2
|
|
167
167
|
|
|
168
168
|
# Always pass through and exit 0
|
|
169
|
-
|
|
169
|
+
printf '%s\n' "$input"
|
|
170
170
|
exit 0
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
9
9
|
input=$(cat)
|
|
10
|
-
tool_output=$(
|
|
10
|
+
tool_output=$(printf '%s\n' "$input" | jq -r '.tool_output // ""')
|
|
11
11
|
|
|
12
12
|
# Skip if output is small (< 3000 chars)
|
|
13
13
|
output_len=${#tool_output}
|
|
14
14
|
if [ "$output_len" -lt 3000 ]; then
|
|
15
|
-
|
|
15
|
+
printf '%s\n' "$input"
|
|
16
16
|
exit 0
|
|
17
17
|
fi
|
|
18
18
|
|
|
@@ -22,7 +22,7 @@ refs=$(echo "$tool_output" | grep -oE 'ref="[^"]*"' | sort -u || true)
|
|
|
22
22
|
# Summarize using Haiku via subscription auth
|
|
23
23
|
summary=$(echo "$tool_output" | claude -p --model haiku "Summarize this browser page content concisely. Preserve ALL ref= attribute values exactly as they appear. Focus on: page structure, interactive elements with their ref values, visible text content, and any error messages." 2>/dev/null) || {
|
|
24
24
|
# Fallback: return original on failure
|
|
25
|
-
|
|
25
|
+
printf '%s\n' "$input"
|
|
26
26
|
exit 0
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -46,5 +46,5 @@ fi
|
|
|
46
46
|
# Return compressed output
|
|
47
47
|
compressed_len=${#summary}
|
|
48
48
|
savings=$(( (output_len - compressed_len) * 100 / output_len ))
|
|
49
|
-
|
|
49
|
+
printf '%s\n' "$input" | jq --arg summary "$summary" --arg savings "${savings}% reduced (${output_len}→${compressed_len} chars)" \
|
|
50
50
|
'.tool_output = $summary | .["updatedMCPToolOutput"] = $summary'
|
|
@@ -12,7 +12,7 @@ input=$(cat)
|
|
|
12
12
|
PLUGIN_CACHE="${HOME}/.claude/shared-plugins/cache"
|
|
13
13
|
|
|
14
14
|
if [ ! -d "$PLUGIN_CACHE" ]; then
|
|
15
|
-
|
|
15
|
+
printf '%s\n' "$input"
|
|
16
16
|
exit 0
|
|
17
17
|
fi
|
|
18
18
|
|
|
@@ -31,5 +31,5 @@ if [ ${#missing[@]} -gt 0 ]; then
|
|
|
31
31
|
done
|
|
32
32
|
fi
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
printf '%s\n' "$input"
|
|
35
35
|
exit 0
|
|
@@ -192,13 +192,26 @@ split("\n")
|
|
|
192
192
|
# 올바르게 분리되어 0/0이었음). 이 조사에서 확정된 실제 원인은 별도 메커니즘이다:
|
|
193
193
|
# tail -n 200 윈도우 안에 경계가 전혀 없을 때 $b=-1로 폴백해 슬라이딩 윈도우 전체를
|
|
194
194
|
# 하나의 turn으로 병합하는 구조 — 본 수정의 승인 범위(0-tool-use 가드 1건) 밖이므로
|
|
195
|
-
# 별도 이슈로 보고한다(오케스트레이터 완료 보고 참조).
|
|
195
|
+
# 별도 이슈로 보고한다(오케스트레이터 완료 보고 참조). → #1628로 등록·수정 완료:
|
|
196
|
+
# 아래 $b 바인딩 직후의 "(#1628)" 주석 및 $wlc 포화 가드 참조.
|
|
196
197
|
| [ range(0; $last + 1)
|
|
197
198
|
| select( ($L[.].message.role? == "user")
|
|
198
199
|
and ( (($L[.].message.content | type) == "string")
|
|
199
200
|
or (([ $L[.].message.content[]? | select(.type? == "tool_result") ] | length) == 0) ) ) ] as $bi
|
|
200
201
|
| (if ($bi | length) > 0 then $bi[-1] else -1 end) as $b
|
|
201
|
-
|
|
202
|
+
# (#1628) 경계가 전혀 없는 경우($bi 비어있음)를 두 케이스로 나눈다:
|
|
203
|
+
# (a) 윈도우가 포화($wlc >= 200 — tail -n 200이 실제로 200줄을 반환) — 윈도우 밖에
|
|
204
|
+
# 진짜 경계가 있었을 수 있다. 이 경우 $b=-1로 윈도우 전체를 하나의 turn으로
|
|
205
|
+
# 병합하면, 서로 독립적이고 각각 컴플라이언트한 여러 응답이 합쳐져 announce/
|
|
206
|
+
# tool_use 카운트가 어긋나 R008 위양성이 5~10건대로 요동친다(#1628 실측). 판정
|
|
207
|
+
# 자체를 스킵한다(empty — 아래에서 result가 비어 exit 0으로 이어진다).
|
|
208
|
+
# (b) 윈도우가 포화되지 않음($wlc < 200 — tail이 transcript 전체를 다 읽었다는 뜻) —
|
|
209
|
+
# 세션이 정말로 짧아 첫 턴부터 지금까지 경계가 없는 것이므로, 기존 $b=-1 폴백을
|
|
210
|
+
# 그대로 유지한다(#1625 찐빠 #3이 확정한 자율 루프 경계 대체 신호와 동일 로직).
|
|
211
|
+
| if ($bi | length) == 0 and $wlc >= 200 then empty
|
|
212
|
+
else
|
|
213
|
+
(
|
|
214
|
+
[ range($b + 1; $last + 1) | $L[.] | select(.message.role? == "assistant") ] as $turn
|
|
202
215
|
| [ $turn[] | .message.content[]? | select(.type? != "thinking") ] as $blocks
|
|
203
216
|
| ($turn[0].uuid? // "") as $tuuid
|
|
204
217
|
| ([ $blocks[] | select(.type? == "text") ][0].text? // "") as $ftext
|
|
@@ -237,10 +250,20 @@ split("\n")
|
|
|
237
250
|
# $nall_tools는 위 forward r008 가드에서 이미 바인딩됨 — 재바인딩하지 않고 재사용한다.
|
|
238
251
|
| (if $nall_tools == 0 and $an_anchored > 0 then $an_anchored else 0 end) as $r008rev
|
|
239
252
|
| [$tuuid, ($r007 | tostring), ($r008 | tostring), ($r008rev | tostring)] | @tsv
|
|
253
|
+
)
|
|
254
|
+
end
|
|
240
255
|
end
|
|
241
256
|
'
|
|
242
257
|
|
|
243
|
-
|
|
258
|
+
# ── 윈도우 포화 여부 판별 (#1628) ──
|
|
259
|
+
# tail -n 200이 실제로 200줄을 반환했는지(포화 — 윈도우 밖에 잘려나간 내용이 있을 수 있음)를
|
|
260
|
+
# jq 호출 전에 bash에서 측정해 $wlc로 전달한다. awk는 트레일링 개행 유무와 무관하게 정확한
|
|
261
|
+
# 레코드 수를 센다(wc -l은 트레일링 개행이 없는 마지막 줄을 놓칠 수 있음).
|
|
262
|
+
window_content=$(tail -n 200 "$TRANSCRIPT_PATH" 2>/dev/null) || window_content=""
|
|
263
|
+
window_line_count=$(printf '%s' "$window_content" | awk 'END{print NR}')
|
|
264
|
+
: "${window_line_count:=0}"
|
|
265
|
+
|
|
266
|
+
result=$(printf '%s' "$window_content" | jq -Rsr --argjson wlc "$window_line_count" "$JQ_LAST_TURN" 2>/dev/null) || result=""
|
|
244
267
|
|
|
245
268
|
if [ -z "$result" ]; then
|
|
246
269
|
exit 0
|
|
@@ -9,9 +9,9 @@ set -euo pipefail
|
|
|
9
9
|
input=$(cat)
|
|
10
10
|
|
|
11
11
|
# Only intercept Bash tool calls
|
|
12
|
-
tool_name=$(
|
|
12
|
+
tool_name=$(printf '%s\n' "$input" | jq -r '.tool // empty' 2>/dev/null || echo "")
|
|
13
13
|
if [ "$tool_name" != "Bash" ]; then
|
|
14
|
-
|
|
14
|
+
printf '%s\n' "$input"
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|
|
@@ -25,26 +25,26 @@ elif command -v rtk >/dev/null 2>&1; then
|
|
|
25
25
|
fi
|
|
26
26
|
|
|
27
27
|
if [ "$RTK_AVAILABLE" != "true" ]; then
|
|
28
|
-
|
|
28
|
+
printf '%s\n' "$input"
|
|
29
29
|
exit 0
|
|
30
30
|
fi
|
|
31
31
|
|
|
32
32
|
# Extract command
|
|
33
|
-
cmd=$(
|
|
33
|
+
cmd=$(printf '%s\n' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null || echo "")
|
|
34
34
|
if [ -z "$cmd" ]; then
|
|
35
|
-
|
|
35
|
+
printf '%s\n' "$input"
|
|
36
36
|
exit 0
|
|
37
37
|
fi
|
|
38
38
|
|
|
39
39
|
# Skip if already using rtk
|
|
40
40
|
if echo "$cmd" | grep -qE '^rtk\b'; then
|
|
41
|
-
|
|
41
|
+
printf '%s\n' "$input"
|
|
42
42
|
exit 0
|
|
43
43
|
fi
|
|
44
44
|
|
|
45
45
|
# Skip complex commands (pipes, redirections, background, subshells, semicolons with multiple commands)
|
|
46
46
|
if echo "$cmd" | grep -qE '[|><&]|;\s*\w'; then
|
|
47
|
-
|
|
47
|
+
printf '%s\n' "$input"
|
|
48
48
|
exit 0
|
|
49
49
|
fi
|
|
50
50
|
|
|
@@ -64,7 +64,7 @@ for rtk_cmd in $RTK_CMDS; do
|
|
|
64
64
|
done
|
|
65
65
|
|
|
66
66
|
if [ "$SUPPORTED" != "true" ]; then
|
|
67
|
-
|
|
67
|
+
printf '%s\n' "$input"
|
|
68
68
|
exit 0
|
|
69
69
|
fi
|
|
70
70
|
|
|
@@ -73,5 +73,5 @@ new_cmd="rtk $cmd"
|
|
|
73
73
|
echo "[RTK] Intercepted: $cmd → $new_cmd" >&2
|
|
74
74
|
|
|
75
75
|
# Output modified JSON
|
|
76
|
-
|
|
76
|
+
printf '%s\n' "$input" | jq --arg new_cmd "$new_cmd" '.tool_input.command = $new_cmd'
|
|
77
77
|
exit 0
|
|
@@ -8,17 +8,17 @@ input=$(cat)
|
|
|
8
8
|
|
|
9
9
|
# Dependency check — allow if jq missing
|
|
10
10
|
if ! command -v jq &>/dev/null; then
|
|
11
|
-
|
|
11
|
+
printf '%s\n' "$input"
|
|
12
12
|
exit 0
|
|
13
13
|
fi
|
|
14
14
|
|
|
15
15
|
# Parse tool input
|
|
16
|
-
tool=$(
|
|
17
|
-
cmd=$(
|
|
16
|
+
tool=$(printf '%s\n' "$input" | jq -r '.tool // ""' 2>/dev/null) || { printf '%s\n' "$input"; exit 0; }
|
|
17
|
+
cmd=$(printf '%s\n' "$input" | jq -r '.tool_input.command // ""' 2>/dev/null) || { printf '%s\n' "$input"; exit 0; }
|
|
18
18
|
|
|
19
19
|
# Only check Bash tool
|
|
20
20
|
if [ "$tool" != "Bash" ]; then
|
|
21
|
-
|
|
21
|
+
printf '%s\n' "$input"
|
|
22
22
|
exit 0
|
|
23
23
|
fi
|
|
24
24
|
|
|
@@ -56,5 +56,5 @@ if echo "$cmd" | grep -qE '(^|\s)(rm|git\s+rm|mv|unlink)\s' && echo "$cmd" | gre
|
|
|
56
56
|
fi
|
|
57
57
|
|
|
58
58
|
# Not a rule deletion — pass through
|
|
59
|
-
|
|
59
|
+
printf '%s\n' "$input"
|
|
60
60
|
exit 0
|
|
@@ -13,14 +13,14 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
13
13
|
input=$(cat)
|
|
14
14
|
|
|
15
15
|
# Extract tool info
|
|
16
|
-
tool_name=$(
|
|
17
|
-
tool_input=$(
|
|
16
|
+
tool_name=$(printf '%s\n' "$input" | jq -r '.tool_name // "unknown"')
|
|
17
|
+
tool_input=$(printf '%s\n' "$input" | jq -r '.tool_input // {}')
|
|
18
18
|
|
|
19
19
|
SCHEMA_FILE=".claude/schemas/tool-inputs.json"
|
|
20
20
|
|
|
21
21
|
# Skip if schema file doesn't exist
|
|
22
22
|
if [ ! -f "$SCHEMA_FILE" ]; then
|
|
23
|
-
|
|
23
|
+
printf '%s\n' "$input"
|
|
24
24
|
exit 0
|
|
25
25
|
fi
|
|
26
26
|
|
|
@@ -28,8 +28,8 @@ warnings=()
|
|
|
28
28
|
|
|
29
29
|
case "$tool_name" in
|
|
30
30
|
"Write")
|
|
31
|
-
file_path=$(
|
|
32
|
-
content=$(
|
|
31
|
+
file_path=$(printf '%s\n' "$tool_input" | jq -r '.file_path // ""')
|
|
32
|
+
content=$(printf '%s\n' "$tool_input" | jq -r '.content // ""')
|
|
33
33
|
|
|
34
34
|
if [ -z "$file_path" ]; then
|
|
35
35
|
warnings+=("[Schema] Write: file_path is empty or missing")
|
|
@@ -40,9 +40,9 @@ case "$tool_name" in
|
|
|
40
40
|
;;
|
|
41
41
|
|
|
42
42
|
"Edit")
|
|
43
|
-
file_path=$(
|
|
44
|
-
old_string=$(
|
|
45
|
-
new_string=$(
|
|
43
|
+
file_path=$(printf '%s\n' "$tool_input" | jq -r '.file_path // ""')
|
|
44
|
+
old_string=$(printf '%s\n' "$tool_input" | jq -r '.old_string // ""')
|
|
45
|
+
new_string=$(printf '%s\n' "$tool_input" | jq -r '.new_string // ""')
|
|
46
46
|
|
|
47
47
|
if [ -z "$file_path" ]; then
|
|
48
48
|
warnings+=("[Schema] Edit: file_path is empty or missing")
|
|
@@ -56,7 +56,7 @@ case "$tool_name" in
|
|
|
56
56
|
;;
|
|
57
57
|
|
|
58
58
|
"Bash")
|
|
59
|
-
command=$(
|
|
59
|
+
command=$(printf '%s\n' "$tool_input" | jq -r '.command // ""')
|
|
60
60
|
|
|
61
61
|
if [ -z "$command" ]; then
|
|
62
62
|
warnings+=("[Schema] Bash: command is empty")
|
|
@@ -102,5 +102,5 @@ if [ ${#warnings[@]} -gt 0 ]; then
|
|
|
102
102
|
fi
|
|
103
103
|
|
|
104
104
|
# Always pass through (Phase 1)
|
|
105
|
-
|
|
105
|
+
printf '%s\n' "$input"
|
|
106
106
|
exit 0
|
|
@@ -13,12 +13,12 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
13
13
|
input=$(cat)
|
|
14
14
|
|
|
15
15
|
# Extract output to scan
|
|
16
|
-
tool_name=$(
|
|
17
|
-
output=$(
|
|
16
|
+
tool_name=$(printf '%s\n' "$input" | jq -r '.tool_name // "unknown"')
|
|
17
|
+
output=$(printf '%s\n' "$input" | jq -r '.tool_output.output // ""')
|
|
18
18
|
|
|
19
19
|
# Skip if no output
|
|
20
20
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
21
|
-
|
|
21
|
+
printf '%s\n' "$input"
|
|
22
22
|
exit 0
|
|
23
23
|
fi
|
|
24
24
|
|
|
@@ -96,5 +96,5 @@ if [ "$detected" = true ]; then
|
|
|
96
96
|
fi
|
|
97
97
|
|
|
98
98
|
# Pass through (always)
|
|
99
|
-
|
|
99
|
+
printf '%s\n' "$input"
|
|
100
100
|
exit 0
|
|
@@ -14,16 +14,16 @@ fi
|
|
|
14
14
|
FINDINGS=$(cat "$FIXES_FILE")
|
|
15
15
|
rm -f "$FIXES_FILE"
|
|
16
16
|
|
|
17
|
-
ISSUE_COUNT=$(
|
|
17
|
+
ISSUE_COUNT=$(printf '%s\n' "$FINDINGS" | jq -r '.issue_count // 0' 2>/dev/null)
|
|
18
18
|
|
|
19
19
|
if [ "$ISSUE_COUNT" -gt 0 ]; then
|
|
20
20
|
echo "[Session Auto-Fix] Previous session left ${ISSUE_COUNT} issue(s):"
|
|
21
|
-
|
|
21
|
+
printf '%s\n' "$FINDINGS" | jq -r '.issues[]' 2>/dev/null | while IFS= read -r issue; do
|
|
22
22
|
type="${issue%%:*}"
|
|
23
23
|
msg="${issue#*:}"
|
|
24
24
|
echo " - [${type}] ${msg}"
|
|
25
25
|
done
|
|
26
|
-
FIX_COUNT=$(
|
|
26
|
+
FIX_COUNT=$(printf '%s\n' "$FINDINGS" | jq -r '.fix_count // 0' 2>/dev/null)
|
|
27
27
|
if [ "$FIX_COUNT" -gt 0 ]; then
|
|
28
28
|
echo "Auto-fixed: ${FIX_COUNT} item(s)."
|
|
29
29
|
fi
|
|
@@ -142,5 +142,5 @@ fi
|
|
|
142
142
|
mkdir -p "$LOG_DIR" 2>/dev/null
|
|
143
143
|
echo "{\"date\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"issue_count\":${ISSUE_COUNT},\"fix_count\":${FIX_COUNT}}" >> "${LOG_DIR}/$(date +%Y-%m-%d).jsonl" 2>/dev/null
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
printf '%s\n' "$input"
|
|
146
146
|
exit 0
|
|
@@ -15,32 +15,32 @@ input=$(cat)
|
|
|
15
15
|
|
|
16
16
|
# ── Opt-out 체크 ──
|
|
17
17
|
if [ "${OMCUSTOM_SESSION_REFLECTION:-}" = "off" ]; then
|
|
18
|
-
|
|
18
|
+
printf '%s\n' "$input"
|
|
19
19
|
exit 0
|
|
20
20
|
fi
|
|
21
21
|
|
|
22
22
|
# ── jq 의존성 체크 ──
|
|
23
23
|
if ! command -v jq >/dev/null 2>&1; then
|
|
24
|
-
|
|
24
|
+
printf '%s\n' "$input"
|
|
25
25
|
exit 0
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
28
|
# ── session_id 추출 ──
|
|
29
|
-
session_id=$(
|
|
29
|
+
session_id=$(printf '%s\n' "$input" | jq -r '.session_id // empty' 2>/dev/null)
|
|
30
30
|
if [ -z "$session_id" ]; then
|
|
31
|
-
|
|
31
|
+
printf '%s\n' "$input"
|
|
32
32
|
exit 0
|
|
33
33
|
fi
|
|
34
34
|
|
|
35
35
|
# ── Phase 2 (#1196): background_tasks / session_crons 추출 (CC v2.1.145+) ──
|
|
36
36
|
# 신규 필드 미존재 시 빈 배열로 처리 (graceful degrade).
|
|
37
|
-
bg_tasks_json=$(
|
|
38
|
-
session_crons_json=$(
|
|
39
|
-
bg_tasks_count=$(
|
|
40
|
-
session_crons_count=$(
|
|
37
|
+
bg_tasks_json=$(printf '%s\n' "$input" | jq -c '.background_tasks // []' 2>/dev/null || echo '[]')
|
|
38
|
+
session_crons_json=$(printf '%s\n' "$input" | jq -c '.session_crons // []' 2>/dev/null || echo '[]')
|
|
39
|
+
bg_tasks_count=$(printf '%s\n' "$bg_tasks_json" | jq 'length' 2>/dev/null || echo 0)
|
|
40
|
+
session_crons_count=$(printf '%s\n' "$session_crons_json" | jq 'length' 2>/dev/null || echo 0)
|
|
41
41
|
|
|
42
42
|
# 미완료 백그라운드 태스크: running/pending/in_progress 상태 카운트
|
|
43
|
-
bg_dangling_count=$(
|
|
43
|
+
bg_dangling_count=$(printf '%s\n' "$bg_tasks_json" | jq '[.[] | select(.status == "running" or .status == "pending" or .status == "in_progress")] | length' 2>/dev/null || echo 0)
|
|
44
44
|
|
|
45
45
|
# ── 경로 결정 (환경변수 override 지원) ──
|
|
46
46
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
@@ -50,7 +50,7 @@ TRANSCRIPT_BASE="${OMCUSTOM_TRANSCRIPT_BASE:-${HOME}/.claude/projects/-Users-san
|
|
|
50
50
|
TRANSCRIPT_PATH="${TRANSCRIPT_BASE}/${session_id}.jsonl"
|
|
51
51
|
|
|
52
52
|
if [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
53
|
-
|
|
53
|
+
printf '%s\n' "$input"
|
|
54
54
|
exit 0
|
|
55
55
|
fi
|
|
56
56
|
|
|
@@ -179,14 +179,14 @@ else
|
|
|
179
179
|
fi
|
|
180
180
|
|
|
181
181
|
# ── Phase 2 (#1196): background_tasks / session_crons 분석 ──
|
|
182
|
-
bg_total=$(
|
|
183
|
-
cron_total=$(
|
|
182
|
+
bg_total=$(printf '%s\n' "$BG_TASKS_JSON" | jq 'length' 2>/dev/null || echo 0)
|
|
183
|
+
cron_total=$(printf '%s\n' "$SESSION_CRONS_JSON" | jq 'length' 2>/dev/null || echo 0)
|
|
184
184
|
bg_dangling_lines=""
|
|
185
185
|
cron_lines=""
|
|
186
186
|
|
|
187
187
|
if [ "$bg_total" -gt 0 ]; then
|
|
188
188
|
# dangling 태스크 목록 (최대 5개): id + status + description (60자 truncate)
|
|
189
|
-
bg_dangling_lines=$(
|
|
189
|
+
bg_dangling_lines=$(printf '%s\n' "$BG_TASKS_JSON" | jq -r '
|
|
190
190
|
[.[] | select(.status == "running" or .status == "pending" or .status == "in_progress")]
|
|
191
191
|
| .[0:5]
|
|
192
192
|
| map(" - id=\(.id // "?") status=\(.status // "?") desc=\((.description // "") | .[0:60])")
|
|
@@ -195,7 +195,7 @@ if [ "$bg_total" -gt 0 ]; then
|
|
|
195
195
|
fi
|
|
196
196
|
|
|
197
197
|
if [ "$cron_total" -gt 0 ]; then
|
|
198
|
-
cron_lines=$(
|
|
198
|
+
cron_lines=$(printf '%s\n' "$SESSION_CRONS_JSON" | jq -r '
|
|
199
199
|
.[0:5]
|
|
200
200
|
| map(" - id=\(.id // "?") schedule=\(.schedule // "?") prompt=\((.prompt // "") | .[0:60])")
|
|
201
201
|
| join("\n")
|
|
@@ -253,5 +253,5 @@ WORKER_ERR_LOG="/tmp/.claude-reflection-err-${PPID}.log"
|
|
|
253
253
|
disown $! 2>/dev/null || true
|
|
254
254
|
|
|
255
255
|
# ── 즉시 stdin pass-through 후 exit 0 (Stop hook 체인 유지) ──
|
|
256
|
-
|
|
256
|
+
printf '%s\n' "$input"
|
|
257
257
|
exit 0
|
|
@@ -12,7 +12,7 @@ PROPOSALS_FILE="/tmp/.claude-skill-proposals-${PPID}"
|
|
|
12
12
|
|
|
13
13
|
# Early exit if no outcomes
|
|
14
14
|
if [ ! -f "$OUTCOMES_FILE" ] || [ ! -s "$OUTCOMES_FILE" ]; then
|
|
15
|
-
|
|
15
|
+
printf '%s\n' "$input"
|
|
16
16
|
exit 0
|
|
17
17
|
fi
|
|
18
18
|
|
|
@@ -45,5 +45,5 @@ fi
|
|
|
45
45
|
|
|
46
46
|
# CRITICAL: Always pass through input and exit 0
|
|
47
47
|
# This hook MUST NEVER block session termination
|
|
48
|
-
|
|
48
|
+
printf '%s\n' "$input"
|
|
49
49
|
exit 0
|
|
@@ -17,18 +17,18 @@ AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
|
|
|
17
17
|
DURATION_FILE="/tmp/.claude-agent-durations-${PPID}"
|
|
18
18
|
|
|
19
19
|
# Skip if no start records exist
|
|
20
|
-
[ -f "$AGENT_START_FILE" ] || {
|
|
20
|
+
[ -f "$AGENT_START_FILE" ] || { printf '%s\n' "$input"; exit 0; }
|
|
21
21
|
|
|
22
22
|
# --- 1. Extract completed agent info ---
|
|
23
|
-
agent_type=$(
|
|
24
|
-
model=$(
|
|
25
|
-
description=$(
|
|
23
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.agent_type // "unknown"')
|
|
24
|
+
model=$(printf '%s\n' "$input" | jq -r '.model // "inherit"')
|
|
25
|
+
description=$(printf '%s\n' "$input" | jq -r '.description // ""' | head -c 80)
|
|
26
26
|
|
|
27
27
|
# --- 2. Calculate duration from start record ---
|
|
28
28
|
start_epoch=$(grep -F "\"agent_type\":\"${agent_type}\"" "$AGENT_START_FILE" 2>/dev/null | tail -1 | jq -r '.start_epoch // "0"' 2>/dev/null || echo "0")
|
|
29
29
|
|
|
30
30
|
if [ "$start_epoch" = "0" ] || [ "$start_epoch" = "null" ]; then
|
|
31
|
-
|
|
31
|
+
printf '%s\n' "$input"
|
|
32
32
|
exit 0
|
|
33
33
|
fi
|
|
34
34
|
|
|
@@ -56,10 +56,10 @@ if [ "$completed_count" -ge 1 ]; then
|
|
|
56
56
|
# Check for still-running agents (in start file but not in duration file)
|
|
57
57
|
if [ -f "$AGENT_START_FILE" ] && [ -s "$AGENT_START_FILE" ]; then
|
|
58
58
|
while IFS= read -r line; do
|
|
59
|
-
running_agent=$(
|
|
60
|
-
running_start=$(
|
|
61
|
-
running_desc=$(
|
|
62
|
-
running_model=$(
|
|
59
|
+
running_agent=$(printf '%s\n' "$line" | jq -r '.agent_type // ""' 2>/dev/null || true)
|
|
60
|
+
running_start=$(printf '%s\n' "$line" | jq -r '.start_epoch // "0"' 2>/dev/null || echo "0")
|
|
61
|
+
running_desc=$(printf '%s\n' "$line" | jq -r '.description // ""' 2>/dev/null || true)
|
|
62
|
+
running_model=$(printf '%s\n' "$line" | jq -r '.model // "inherit"' 2>/dev/null || true)
|
|
63
63
|
|
|
64
64
|
if [ "$running_start" = "0" ] || [ "$running_start" = "null" ]; then continue; fi
|
|
65
65
|
|
|
@@ -90,7 +90,7 @@ duration_entry=$(jq -cn \
|
|
|
90
90
|
--arg ts "$now_epoch" \
|
|
91
91
|
'{agent_type: $agent, model: $model, description: $desc, duration_seconds: ($dur | tonumber), timestamp: $ts}')
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
printf '%s\n' "$duration_entry" >> "$DURATION_FILE"
|
|
94
94
|
|
|
95
95
|
# Remove only first consumed start entry (preserve siblings for parallel same-type agents)
|
|
96
96
|
if [ -f "$AGENT_START_FILE" ]; then
|
|
@@ -108,5 +108,5 @@ if [ -f "$DURATION_FILE" ]; then
|
|
|
108
108
|
fi
|
|
109
109
|
|
|
110
110
|
# Pass through
|
|
111
|
-
|
|
111
|
+
printf '%s\n' "$input"
|
|
112
112
|
exit 0
|