oh-my-customcode 0.76.2 → 0.78.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 +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/hooks/hooks.json +9 -1
- package/templates/.claude/hooks/scripts/agent-start-recorder.sh +40 -0
- package/templates/.claude/hooks/scripts/stall-detection-advisor.sh +112 -0
- package/templates/.claude/hooks/scripts/task-outcome-recorder.sh +15 -1
- package/templates/manifest.json +1 -1
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -166,9 +166,13 @@
|
|
|
166
166
|
{
|
|
167
167
|
"type": "command",
|
|
168
168
|
"command": "#!/bin/bash\ninput=$(cat)\nagent_type=$(echo \"$input\" | jq -r '.agent_type // \"unknown\"')\nmodel=$(echo \"$input\" | jq -r '.model // \"inherit\"')\ndesc=$(echo \"$input\" | jq -r '.description // \"\"' | head -c 40)\necho \"─── [SubagentStart] ${agent_type}:${model} | ${desc} ───\" >&2\necho \"$input\""
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"type": "command",
|
|
172
|
+
"command": "bash .claude/hooks/scripts/agent-start-recorder.sh"
|
|
169
173
|
}
|
|
170
174
|
],
|
|
171
|
-
"description": "HUD display
|
|
175
|
+
"description": "HUD display + agent start time recording for stall detection (R009)"
|
|
172
176
|
}
|
|
173
177
|
],
|
|
174
178
|
"SubagentStop": [
|
|
@@ -179,6 +183,10 @@
|
|
|
179
183
|
"type": "command",
|
|
180
184
|
"command": "bash .claude/hooks/scripts/task-outcome-recorder.sh"
|
|
181
185
|
},
|
|
186
|
+
{
|
|
187
|
+
"type": "command",
|
|
188
|
+
"command": "bash .claude/hooks/scripts/stall-detection-advisor.sh"
|
|
189
|
+
},
|
|
182
190
|
{
|
|
183
191
|
"type": "command",
|
|
184
192
|
"command": "count_file=\"/tmp/.claude-loop-count-$PPID\"; if [ -f \"$count_file\" ]; then last_mod=$(stat -c%Y \"$count_file\" 2>/dev/null || stat -f%m \"$count_file\" 2>/dev/null || echo 0); now=$(date +%s); if [ $((now - last_mod)) -gt 60 ]; then echo 0 > \"$count_file\"; fi; fi; count=$(cat \"$count_file\" 2>/dev/null || echo 0); count=$((count + 1)); echo \"$count\" > \"$count_file\"; if [ \"$count\" -ge 4 ]; then echo '[AutoContinue] SAFETY: auto-continue limit (3) reached. Pausing.' >&2; fi; cat"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Agent Start Recorder
|
|
5
|
+
# Trigger: SubagentStart
|
|
6
|
+
# Purpose: Record agent spawn time for stall detection duration calculations
|
|
7
|
+
# Protocol: stdin JSON -> record start time -> stdout pass-through, exit 0 always (R021 advisory)
|
|
8
|
+
|
|
9
|
+
command -v jq >/dev/null 2>&1 || { cat; exit 0; }
|
|
10
|
+
|
|
11
|
+
input=$(cat)
|
|
12
|
+
|
|
13
|
+
agent_type=$(echo "$input" | jq -r '.agent_type // "unknown"')
|
|
14
|
+
model=$(echo "$input" | jq -r '.model // "inherit"')
|
|
15
|
+
description=$(echo "$input" | jq -r '.description // ""' | head -c 80)
|
|
16
|
+
|
|
17
|
+
AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
|
|
18
|
+
|
|
19
|
+
timestamp=$(date +%s)
|
|
20
|
+
|
|
21
|
+
entry=$(jq -cn \
|
|
22
|
+
--arg ts "$timestamp" \
|
|
23
|
+
--arg agent "$agent_type" \
|
|
24
|
+
--arg model "$model" \
|
|
25
|
+
--arg desc "$description" \
|
|
26
|
+
'{start_epoch: $ts, agent_type: $agent, model: $model, description: $desc}')
|
|
27
|
+
|
|
28
|
+
echo "$entry" >> "$AGENT_START_FILE"
|
|
29
|
+
|
|
30
|
+
# Ring buffer: 50 max
|
|
31
|
+
if [ -f "$AGENT_START_FILE" ]; then
|
|
32
|
+
line_count=$(wc -l < "$AGENT_START_FILE" | tr -d ' ')
|
|
33
|
+
if [ "$line_count" -gt 50 ]; then
|
|
34
|
+
tail -50 "$AGENT_START_FILE" > "${AGENT_START_FILE}.tmp"
|
|
35
|
+
mv "${AGENT_START_FILE}.tmp" "$AGENT_START_FILE"
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "$input"
|
|
40
|
+
exit 0
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Stall Detection Advisor
|
|
5
|
+
# Trigger: SubagentStop
|
|
6
|
+
# Purpose: Detect stalled parallel agents and advise adaptive splitting (R009)
|
|
7
|
+
# Protocol: stdin JSON -> analyze durations -> stderr advisory, stdout pass-through, exit 0 always (R021)
|
|
8
|
+
|
|
9
|
+
# ORDERING: This hook MUST run AFTER task-outcome-recorder.sh in hooks.json SubagentStop array.
|
|
10
|
+
# Reason: This script removes consumed entries from AGENT_START_FILE; task-outcome-recorder reads them first.
|
|
11
|
+
|
|
12
|
+
command -v jq >/dev/null 2>&1 || { cat; exit 0; }
|
|
13
|
+
|
|
14
|
+
input=$(cat)
|
|
15
|
+
|
|
16
|
+
AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
|
|
17
|
+
DURATION_FILE="/tmp/.claude-agent-durations-${PPID}"
|
|
18
|
+
|
|
19
|
+
# Skip if no start records exist
|
|
20
|
+
[ -f "$AGENT_START_FILE" ] || { echo "$input"; exit 0; }
|
|
21
|
+
|
|
22
|
+
# --- 1. Extract completed agent info ---
|
|
23
|
+
agent_type=$(echo "$input" | jq -r '.agent_type // "unknown"')
|
|
24
|
+
model=$(echo "$input" | jq -r '.model // "inherit"')
|
|
25
|
+
description=$(echo "$input" | jq -r '.description // ""' | head -c 80)
|
|
26
|
+
|
|
27
|
+
# --- 2. Calculate duration from start record ---
|
|
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
|
+
|
|
30
|
+
if [ "$start_epoch" = "0" ] || [ "$start_epoch" = "null" ]; then
|
|
31
|
+
echo "$input"
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
now_epoch=$(date +%s)
|
|
36
|
+
duration_seconds=$((now_epoch - start_epoch))
|
|
37
|
+
|
|
38
|
+
# Guard against negative duration (NTP adjustment, clock skew)
|
|
39
|
+
if [ "$duration_seconds" -lt 0 ]; then duration_seconds=0; fi
|
|
40
|
+
|
|
41
|
+
# --- 3. Stall detection (BEFORE recording this agent's duration, so self is excluded from average) ---
|
|
42
|
+
# Need at least 1 completed peer to calculate average
|
|
43
|
+
if [ -f "$DURATION_FILE" ]; then
|
|
44
|
+
completed_count=$(wc -l < "$DURATION_FILE" | tr -d ' ')
|
|
45
|
+
else
|
|
46
|
+
completed_count=0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ "$completed_count" -ge 1 ]; then
|
|
50
|
+
# Calculate average duration of completed agents (null-safe)
|
|
51
|
+
avg_duration=$(jq -s '[.[].duration_seconds | numbers] | if length == 0 then 0 else add / length | floor end' "$DURATION_FILE" 2>/dev/null || echo "0")
|
|
52
|
+
|
|
53
|
+
if [ "$avg_duration" -gt 0 ]; then
|
|
54
|
+
stall_threshold=$((avg_duration * 2))
|
|
55
|
+
|
|
56
|
+
# Check for still-running agents (in start file but not in duration file)
|
|
57
|
+
if [ -f "$AGENT_START_FILE" ] && [ -s "$AGENT_START_FILE" ]; then
|
|
58
|
+
while IFS= read -r line; do
|
|
59
|
+
running_agent=$(echo "$line" | jq -r '.agent_type // ""' 2>/dev/null || true)
|
|
60
|
+
running_start=$(echo "$line" | jq -r '.start_epoch // "0"' 2>/dev/null || echo "0")
|
|
61
|
+
running_desc=$(echo "$line" | jq -r '.description // ""' 2>/dev/null || true)
|
|
62
|
+
running_model=$(echo "$line" | jq -r '.model // "inherit"' 2>/dev/null || true)
|
|
63
|
+
|
|
64
|
+
if [ "$running_start" = "0" ] || [ "$running_start" = "null" ]; then continue; fi
|
|
65
|
+
|
|
66
|
+
elapsed=$((now_epoch - running_start))
|
|
67
|
+
|
|
68
|
+
if [ "$elapsed" -gt "$stall_threshold" ]; then
|
|
69
|
+
# --- Emit advisory (stderr) ---
|
|
70
|
+
echo "" >&2
|
|
71
|
+
echo "─── [Stall Detection Advisory] ───────────────────────────" >&2
|
|
72
|
+
echo " Stalled: ${running_agent}:${running_model} (${elapsed}s elapsed, 2x avg ${avg_duration}s)" >&2
|
|
73
|
+
echo " Description: ${running_desc}" >&2
|
|
74
|
+
echo " ⚡ Consider spawning independent pending tasks immediately" >&2
|
|
75
|
+
echo " R009 Adaptive Parallel Splitting applies" >&2
|
|
76
|
+
echo "──────────────────────────────────────────────────────────" >&2
|
|
77
|
+
echo "" >&2
|
|
78
|
+
fi
|
|
79
|
+
done < "$AGENT_START_FILE"
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# --- 4. Record duration (AFTER stall detection so self is excluded from average) ---
|
|
85
|
+
duration_entry=$(jq -cn \
|
|
86
|
+
--arg agent "$agent_type" \
|
|
87
|
+
--arg model "$model" \
|
|
88
|
+
--arg desc "$description" \
|
|
89
|
+
--arg dur "$duration_seconds" \
|
|
90
|
+
--arg ts "$now_epoch" \
|
|
91
|
+
'{agent_type: $agent, model: $model, description: $desc, duration_seconds: ($dur | tonumber), timestamp: $ts}')
|
|
92
|
+
|
|
93
|
+
echo "$duration_entry" >> "$DURATION_FILE"
|
|
94
|
+
|
|
95
|
+
# Remove only first consumed start entry (preserve siblings for parallel same-type agents)
|
|
96
|
+
if [ -f "$AGENT_START_FILE" ]; then
|
|
97
|
+
awk -v pat="\"agent_type\":\"${agent_type}\"" 'found || $0 !~ pat { print; next } { found=1 }' "$AGENT_START_FILE" > "${AGENT_START_FILE}.tmp" 2>/dev/null || true
|
|
98
|
+
mv "${AGENT_START_FILE}.tmp" "$AGENT_START_FILE" 2>/dev/null || true
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Ring buffer: 50 max
|
|
102
|
+
if [ -f "$DURATION_FILE" ]; then
|
|
103
|
+
line_count=$(wc -l < "$DURATION_FILE" | tr -d ' ')
|
|
104
|
+
if [ "$line_count" -gt 50 ]; then
|
|
105
|
+
tail -50 "$DURATION_FILE" > "${DURATION_FILE}.tmp"
|
|
106
|
+
mv "${DURATION_FILE}.tmp" "$DURATION_FILE"
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Pass through
|
|
111
|
+
echo "$input"
|
|
112
|
+
exit 0
|
|
@@ -67,6 +67,19 @@ else
|
|
|
67
67
|
fi
|
|
68
68
|
fi
|
|
69
69
|
|
|
70
|
+
# Duration calculation from start recorder
|
|
71
|
+
# ORDERING: This script MUST run BEFORE stall-detection-advisor.sh in hooks.json SubagentStop array.
|
|
72
|
+
# Reason: stall-detection-advisor removes consumed entries from AGENT_START_FILE after reading.
|
|
73
|
+
AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
|
|
74
|
+
duration_seconds=0
|
|
75
|
+
if [ -f "$AGENT_START_FILE" ]; then
|
|
76
|
+
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")
|
|
77
|
+
if [ "$start_epoch" != "0" ] && [ "$start_epoch" != "null" ]; then
|
|
78
|
+
now_epoch=$(date +%s)
|
|
79
|
+
duration_seconds=$((now_epoch - start_epoch))
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
|
|
70
83
|
# Append JSON line entry
|
|
71
84
|
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
72
85
|
entry=$(jq -n \
|
|
@@ -78,7 +91,8 @@ entry=$(jq -n \
|
|
|
78
91
|
--arg skill "$skill_name" \
|
|
79
92
|
--arg desc "$description" \
|
|
80
93
|
--arg err "$error_summary" \
|
|
81
|
-
|
|
94
|
+
--arg dur "$duration_seconds" \
|
|
95
|
+
'{timestamp: $ts, agent_type: $agent, model: $model, outcome: $outcome, pattern_used: $pattern, skill: $skill, description: $desc, error_summary: $err, duration_seconds: ($dur | tonumber)}')
|
|
82
96
|
|
|
83
97
|
echo "$entry" >> "$OUTCOME_FILE"
|
|
84
98
|
|
package/templates/manifest.json
CHANGED