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 CHANGED
@@ -9325,7 +9325,7 @@ var init_package = __esm(() => {
9325
9325
  workspaces: [
9326
9326
  "packages/*"
9327
9327
  ],
9328
- version: "0.76.2",
9328
+ version: "0.78.0",
9329
9329
  description: "Batteries-included agent harness for Claude Code",
9330
9330
  type: "module",
9331
9331
  bin: {
package/dist/index.js CHANGED
@@ -1820,7 +1820,7 @@ var package_default = {
1820
1820
  workspaces: [
1821
1821
  "packages/*"
1822
1822
  ],
1823
- version: "0.76.2",
1823
+ version: "0.78.0",
1824
1824
  description: "Batteries-included agent harness for Claude Code",
1825
1825
  type: "module",
1826
1826
  bin: {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "0.76.2",
6
+ "version": "0.78.0",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -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 when a subagent starts (complements PreToolUse Agent matcher)"
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
- '{timestamp: $ts, agent_type: $agent, model: $model, outcome: $outcome, pattern_used: $pattern, skill: $skill, description: $desc, error_summary: $err}')
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
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.76.2",
2
+ "version": "0.78.0",
3
3
  "lastUpdated": "2026-03-24T00:00:00.000Z",
4
4
  "components": [
5
5
  {