oh-my-customcode 1.1.55 → 1.1.57
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 +5 -1
- package/dist/index.js +5 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +21 -21
- 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/claude-md-reinject.sh +9 -4
- 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/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 +5 -5
- 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 +21 -21
- package/templates/manifest.json +1 -1
|
@@ -8,16 +8,16 @@ set -euo pipefail
|
|
|
8
8
|
input=$(cat)
|
|
9
9
|
|
|
10
10
|
# Dependencies check
|
|
11
|
-
command -v jq >/dev/null 2>&1 || {
|
|
12
|
-
command -v sqlite3 >/dev/null 2>&1 || {
|
|
11
|
+
command -v jq >/dev/null 2>&1 || { printf '%s\n' "$input"; exit 0; }
|
|
12
|
+
command -v sqlite3 >/dev/null 2>&1 || { printf '%s\n' "$input"; exit 0; }
|
|
13
13
|
|
|
14
14
|
# PID scoping
|
|
15
15
|
OUTCOMES_FILE="/tmp/.claude-task-outcomes-${PPID}"
|
|
16
|
-
[ -f "$OUTCOMES_FILE" ] || {
|
|
16
|
+
[ -f "$OUTCOMES_FILE" ] || { printf '%s\n' "$input"; exit 0; }
|
|
17
17
|
|
|
18
18
|
# DB path
|
|
19
19
|
DB_PATH="${HOME}/.config/oh-my-customcode/eval-core.sqlite"
|
|
20
|
-
[ -f "$DB_PATH" ] || {
|
|
20
|
+
[ -f "$DB_PATH" ] || { printf '%s\n' "$input"; exit 0; }
|
|
21
21
|
|
|
22
22
|
# Log file for error diagnostics
|
|
23
23
|
LOG_FILE="/tmp/.claude-feedback-collector-${PPID}.log"
|
|
@@ -30,8 +30,8 @@ declare -A FAILURE_COUNTS
|
|
|
30
30
|
declare -A TOTAL_COUNTS
|
|
31
31
|
|
|
32
32
|
while IFS= read -r line; do
|
|
33
|
-
agent_type=$(
|
|
34
|
-
outcome=$(
|
|
33
|
+
agent_type=$(printf '%s\n' "$line" | jq -r '.agent_type // empty' 2>/dev/null) || continue
|
|
34
|
+
outcome=$(printf '%s\n' "$line" | jq -r '.outcome // empty' 2>/dev/null) || continue
|
|
35
35
|
[ -z "$agent_type" ] && continue
|
|
36
36
|
|
|
37
37
|
TOTAL_COUNTS[$agent_type]=$(( ${TOTAL_COUNTS[$agent_type]:-0} + 1 ))
|
|
@@ -88,5 +88,5 @@ fi
|
|
|
88
88
|
|
|
89
89
|
# CRITICAL: Always pass through input and exit 0
|
|
90
90
|
# This hook MUST NEVER block session termination
|
|
91
|
-
|
|
91
|
+
printf '%s\n' "$input"
|
|
92
92
|
exit 0
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
# Advisory warning when files are modified outside Claude Code
|
|
4
4
|
|
|
5
5
|
input=$(cat)
|
|
6
|
-
file_path=$(
|
|
7
|
-
change_type=$(
|
|
6
|
+
file_path=$(printf '%s\n' "$input" | jq -r '.file_path // ""' 2>/dev/null)
|
|
7
|
+
change_type=$(printf '%s\n' "$input" | jq -r '.change_type // "modified"' 2>/dev/null)
|
|
8
8
|
|
|
9
9
|
if [ -z "$file_path" ]; then
|
|
10
|
-
|
|
10
|
+
printf '%s\n' "$input"
|
|
11
11
|
exit 0
|
|
12
12
|
fi
|
|
13
13
|
|
|
@@ -23,4 +23,4 @@ case "$file_path" in
|
|
|
23
23
|
;;
|
|
24
24
|
esac
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
printf '%s\n' "$input"
|
|
@@ -14,8 +14,8 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
14
14
|
|
|
15
15
|
input=$(cat)
|
|
16
16
|
|
|
17
|
-
agent_type=$(
|
|
18
|
-
prompt=$(
|
|
17
|
+
agent_type=$(printf '%s\n' "$input" | jq -r '.tool_input.subagent_type // ""')
|
|
18
|
+
prompt=$(printf '%s\n' "$input" | jq -r '.tool_input.prompt // ""')
|
|
19
19
|
|
|
20
20
|
# R010 violation tracking file (PPID-scoped for session persistence)
|
|
21
21
|
VIOLATION_FILE="/tmp/.claude-r010-violations-${PPID}"
|
|
@@ -54,4 +54,4 @@ if [ "$agent_type" != "mgr-gitnerd" ]; then
|
|
|
54
54
|
fi
|
|
55
55
|
|
|
56
56
|
# Always pass through - this hook is advisory only
|
|
57
|
-
|
|
57
|
+
printf '%s\n' "$input"
|
|
@@ -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
|
|
@@ -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
|
|
@@ -203,7 +203,7 @@ entry=$(jq -cn \
|
|
|
203
203
|
--arg readonly "$is_readonly" \
|
|
204
204
|
'{timestamp: $ts, tool: $tool, path: $path, is_error: $err, error_hash: $hash, preview: $preview, readonly: $readonly}')
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
printf '%s\n' "$entry" >> "$HISTORY_FILE"
|
|
207
207
|
|
|
208
208
|
# Ring buffer: keep last 100 entries
|
|
209
209
|
if [ -f "$HISTORY_FILE" ]; then
|
|
@@ -218,13 +218,13 @@ fi
|
|
|
218
218
|
|
|
219
219
|
# Only check for patterns if we have enough history
|
|
220
220
|
if [ ! -f "$HISTORY_FILE" ]; then
|
|
221
|
-
|
|
221
|
+
printf '%s\n' "$input"
|
|
222
222
|
exit 0
|
|
223
223
|
fi
|
|
224
224
|
|
|
225
225
|
recent_count=$(wc -l < "$HISTORY_FILE")
|
|
226
226
|
if [ "$recent_count" -lt 3 ]; then
|
|
227
|
-
|
|
227
|
+
printf '%s\n' "$input"
|
|
228
228
|
exit 0
|
|
229
229
|
fi
|
|
230
230
|
|
|
@@ -347,7 +347,7 @@ if [ "$hard_block" = true ]; then
|
|
|
347
347
|
echo " Action: Blocking this tool call to break the stuck loop." >&2
|
|
348
348
|
echo " Recovery: Step back, re-read the error, and try a fundamentally different approach." >&2
|
|
349
349
|
echo "=====================================" >&2
|
|
350
|
-
|
|
350
|
+
printf '%s\n' "$input"
|
|
351
351
|
HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
|
|
352
352
|
if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
|
|
353
353
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
@@ -357,7 +357,7 @@ if [ "$hard_block" = true ]; then
|
|
|
357
357
|
fi
|
|
358
358
|
|
|
359
359
|
# Pass through
|
|
360
|
-
|
|
360
|
+
printf '%s\n' "$input"
|
|
361
361
|
HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
|
|
362
362
|
if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
|
|
363
363
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|