oh-my-claude-sisyphus 3.8.2 → 3.8.4
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +14 -1
- package/dist/__tests__/installer.test.js +1 -1
- package/dist/__tests__/installer.test.js.map +1 -1
- package/dist/installer/index.d.ts +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -1
- package/dist/installer/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/hooks/keyword-detector.mjs +28 -4
- package/templates/hooks/persistent-mode.mjs +4 -4
- package/templates/hooks/post-tool-use.mjs +5 -2
- package/templates/hooks/pre-tool-use.mjs +14 -2
- package/templates/hooks/session-start.mjs +102 -2
- package/templates/hooks/stop-continuation.mjs +1 -1
- package/templates/hooks/keyword-detector.sh +0 -268
- package/templates/hooks/persistent-mode.sh +0 -244
- package/templates/hooks/post-tool-use.sh +0 -90
- package/templates/hooks/pre-tool-use.sh +0 -113
- package/templates/hooks/session-start.sh +0 -62
- package/templates/hooks/stop-continuation.sh +0 -93
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# OMC Keyword Detector Hook (Bash)
|
|
3
|
-
# Detects magic keywords and invokes skill tools
|
|
4
|
-
# Linux/macOS compatible
|
|
5
|
-
#
|
|
6
|
-
# Supported keywords (in priority order):
|
|
7
|
-
# 1. cancel: Stop active modes
|
|
8
|
-
# 2. ralph: Persistence mode until task completion
|
|
9
|
-
# 3. autopilot: Full autonomous execution
|
|
10
|
-
# 4. ultrapilot: Parallel autopilot
|
|
11
|
-
# 5. ultrawork/ulw: Maximum parallel execution
|
|
12
|
-
# 6. ecomode/eco: Token-efficient execution
|
|
13
|
-
# 7. swarm: N coordinated agents
|
|
14
|
-
# 8. pipeline: Sequential agent chaining
|
|
15
|
-
# 9. ralplan: Iterative planning with consensus
|
|
16
|
-
# 10. plan: Planning interview mode
|
|
17
|
-
# 11. tdd: Test-driven development
|
|
18
|
-
# 12. research: Research orchestration
|
|
19
|
-
# 13. ultrathink/think: Extended reasoning
|
|
20
|
-
# 14. deepsearch: Codebase search (restricted patterns)
|
|
21
|
-
# 15. analyze: Analysis mode (restricted patterns)
|
|
22
|
-
|
|
23
|
-
# Read stdin (JSON input from Claude Code)
|
|
24
|
-
INPUT=$(cat)
|
|
25
|
-
|
|
26
|
-
# Extract directory from input
|
|
27
|
-
DIRECTORY=""
|
|
28
|
-
if command -v jq &> /dev/null; then
|
|
29
|
-
DIRECTORY=$(echo "$INPUT" | jq -r '.directory // ""' 2>/dev/null)
|
|
30
|
-
fi
|
|
31
|
-
if [ -z "$DIRECTORY" ] || [ "$DIRECTORY" = "null" ]; then
|
|
32
|
-
DIRECTORY=$(pwd)
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
# Extract the prompt text - try multiple JSON paths
|
|
36
|
-
PROMPT=""
|
|
37
|
-
if command -v jq &> /dev/null; then
|
|
38
|
-
# Try to extract from various possible JSON structures
|
|
39
|
-
PROMPT=$(echo "$INPUT" | jq -r '
|
|
40
|
-
if .prompt then .prompt
|
|
41
|
-
elif .message.content then .message.content
|
|
42
|
-
elif .parts then ([.parts[] | select(.type == "text") | .text] | join(" "))
|
|
43
|
-
else ""
|
|
44
|
-
end
|
|
45
|
-
' 2>/dev/null)
|
|
46
|
-
fi
|
|
47
|
-
|
|
48
|
-
# Fallback: simple grep extraction if jq fails
|
|
49
|
-
if [ -z "$PROMPT" ] || [ "$PROMPT" = "null" ]; then
|
|
50
|
-
PROMPT=$(echo "$INPUT" | grep -oP '"(prompt|content|text)"\s*:\s*"\K[^"]+' | head -1)
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
# Exit if no prompt found
|
|
54
|
-
if [ -z "$PROMPT" ]; then
|
|
55
|
-
echo '{"continue": true}'
|
|
56
|
-
exit 0
|
|
57
|
-
fi
|
|
58
|
-
|
|
59
|
-
# Remove code blocks before checking keywords (prevents false positives)
|
|
60
|
-
PROMPT_NO_CODE=$(echo "$PROMPT" | sed 's/```[^`]*```//g' | sed 's/`[^`]*`//g')
|
|
61
|
-
|
|
62
|
-
# Convert to lowercase for case-insensitive matching
|
|
63
|
-
PROMPT_LOWER=$(echo "$PROMPT_NO_CODE" | tr '[:upper:]' '[:lower:]')
|
|
64
|
-
|
|
65
|
-
# Create a skill invocation message that tells Claude to use the Skill tool
|
|
66
|
-
create_skill_invocation() {
|
|
67
|
-
local skill_name="$1"
|
|
68
|
-
local original_prompt="$2"
|
|
69
|
-
local args="$3"
|
|
70
|
-
|
|
71
|
-
local args_section=""
|
|
72
|
-
if [ -n "$args" ]; then
|
|
73
|
-
args_section="\\nArguments: $args"
|
|
74
|
-
fi
|
|
75
|
-
|
|
76
|
-
local skill_upper=$(echo "$skill_name" | tr '[:lower:]' '[:upper:]')
|
|
77
|
-
|
|
78
|
-
cat << EOF
|
|
79
|
-
[MAGIC KEYWORD: ${skill_upper}]
|
|
80
|
-
|
|
81
|
-
You MUST invoke the skill using the Skill tool:
|
|
82
|
-
|
|
83
|
-
Skill: oh-my-claudecode:${skill_name}${args_section}
|
|
84
|
-
|
|
85
|
-
User request:
|
|
86
|
-
${original_prompt}
|
|
87
|
-
|
|
88
|
-
IMPORTANT: Invoke the skill IMMEDIATELY. Do not proceed without loading the skill instructions.
|
|
89
|
-
EOF
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
# Clear state files for cancel operation
|
|
93
|
-
clear_state_files() {
|
|
94
|
-
local directory="$1"
|
|
95
|
-
local modes=("ralph" "autopilot" "ultrapilot" "ultrawork" "ecomode" "swarm" "pipeline")
|
|
96
|
-
|
|
97
|
-
for mode in "${modes[@]}"; do
|
|
98
|
-
rm -f "$directory/.omc/state/${mode}-state.json" 2>/dev/null
|
|
99
|
-
rm -f "$HOME/.omc/state/${mode}-state.json" 2>/dev/null
|
|
100
|
-
done
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
# Activate state for a mode
|
|
104
|
-
activate_state() {
|
|
105
|
-
local directory="$1"
|
|
106
|
-
local prompt="$2"
|
|
107
|
-
local state_name="$3"
|
|
108
|
-
|
|
109
|
-
# Create directories
|
|
110
|
-
mkdir -p "$directory/.omc/state" 2>/dev/null
|
|
111
|
-
mkdir -p "$HOME/.omc/state" 2>/dev/null
|
|
112
|
-
|
|
113
|
-
# Escape prompt for JSON
|
|
114
|
-
local prompt_escaped=$(echo "$prompt" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | tr '\n' ' ')
|
|
115
|
-
local timestamp=$(date -Iseconds 2>/dev/null || date +%Y-%m-%dT%H:%M:%S%z)
|
|
116
|
-
|
|
117
|
-
local state_json="{
|
|
118
|
-
\"active\": true,
|
|
119
|
-
\"started_at\": \"$timestamp\",
|
|
120
|
-
\"original_prompt\": \"$prompt_escaped\",
|
|
121
|
-
\"reinforcement_count\": 0,
|
|
122
|
-
\"last_checked_at\": \"$timestamp\"
|
|
123
|
-
}"
|
|
124
|
-
|
|
125
|
-
# Write state to both local and global locations
|
|
126
|
-
echo "$state_json" > "$directory/.omc/state/${state_name}-state.json" 2>/dev/null
|
|
127
|
-
echo "$state_json" > "$HOME/.omc/state/${state_name}-state.json" 2>/dev/null
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
# Output JSON with skill invocation message
|
|
131
|
-
output_skill() {
|
|
132
|
-
local skill_name="$1"
|
|
133
|
-
local prompt="$2"
|
|
134
|
-
local args="$3"
|
|
135
|
-
|
|
136
|
-
local message=$(create_skill_invocation "$skill_name" "$prompt" "$args")
|
|
137
|
-
# Escape for JSON: backslashes, quotes, and newlines
|
|
138
|
-
local escaped_message=$(echo "$message" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | awk '{printf "%s\\n", $0}' | sed 's/\\n$//')
|
|
139
|
-
|
|
140
|
-
echo "{\"continue\": true, \"message\": \"$escaped_message\"}"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
# Priority 1: Cancel (BEFORE other modes - clears states)
|
|
144
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(stop|cancel|abort)\b'; then
|
|
145
|
-
clear_state_files "$DIRECTORY"
|
|
146
|
-
output_skill "cancel" "$PROMPT"
|
|
147
|
-
exit 0
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
|
-
# Priority 2: Ralph keywords
|
|
151
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(ralph|don'\''t stop|must complete|until done)\b'; then
|
|
152
|
-
activate_state "$DIRECTORY" "$PROMPT" "ralph"
|
|
153
|
-
activate_state "$DIRECTORY" "$PROMPT" "ultrawork"
|
|
154
|
-
output_skill "ralph" "$PROMPT"
|
|
155
|
-
exit 0
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
# Priority 3: Autopilot keywords
|
|
159
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(autopilot|auto pilot|auto-pilot|autonomous|full auto|fullsend)\b' || \
|
|
160
|
-
echo "$PROMPT_LOWER" | grep -qE '\bbuild\s+me\s+' || \
|
|
161
|
-
echo "$PROMPT_LOWER" | grep -qE '\bcreate\s+me\s+' || \
|
|
162
|
-
echo "$PROMPT_LOWER" | grep -qE '\bmake\s+me\s+' || \
|
|
163
|
-
echo "$PROMPT_LOWER" | grep -qE '\bi\s+want\s+a\s+' || \
|
|
164
|
-
echo "$PROMPT_LOWER" | grep -qE '\bi\s+want\s+an\s+' || \
|
|
165
|
-
echo "$PROMPT_LOWER" | grep -qE '\bhandle\s+it\s+all\b' || \
|
|
166
|
-
echo "$PROMPT_LOWER" | grep -qE '\bend\s+to\s+end\b' || \
|
|
167
|
-
echo "$PROMPT_LOWER" | grep -qE '\be2e\s+this\b'; then
|
|
168
|
-
activate_state "$DIRECTORY" "$PROMPT" "autopilot"
|
|
169
|
-
output_skill "autopilot" "$PROMPT"
|
|
170
|
-
exit 0
|
|
171
|
-
fi
|
|
172
|
-
|
|
173
|
-
# Priority 4: Ultrapilot
|
|
174
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(ultrapilot|ultra-pilot)\b' || \
|
|
175
|
-
echo "$PROMPT_LOWER" | grep -qE '\bparallel\s+build\b' || \
|
|
176
|
-
echo "$PROMPT_LOWER" | grep -qE '\bswarm\s+build\b'; then
|
|
177
|
-
activate_state "$DIRECTORY" "$PROMPT" "ultrapilot"
|
|
178
|
-
output_skill "ultrapilot" "$PROMPT"
|
|
179
|
-
exit 0
|
|
180
|
-
fi
|
|
181
|
-
|
|
182
|
-
# Priority 5: Ultrawork keywords
|
|
183
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(ultrawork|ulw|uw)\b'; then
|
|
184
|
-
activate_state "$DIRECTORY" "$PROMPT" "ultrawork"
|
|
185
|
-
output_skill "ultrawork" "$PROMPT"
|
|
186
|
-
exit 0
|
|
187
|
-
fi
|
|
188
|
-
|
|
189
|
-
# Priority 6: Ecomode keywords
|
|
190
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(eco|ecomode|eco-mode|efficient|save-tokens|budget)\b'; then
|
|
191
|
-
activate_state "$DIRECTORY" "$PROMPT" "ecomode"
|
|
192
|
-
output_skill "ecomode" "$PROMPT"
|
|
193
|
-
exit 0
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
|
-
# Priority 7: Swarm - parse N from "swarm N agents"
|
|
197
|
-
SWARM_MATCH=$(echo "$PROMPT_LOWER" | grep -oE '\bswarm\s+[0-9]+\s+agents?\b' | grep -oE '[0-9]+')
|
|
198
|
-
if [ -n "$SWARM_MATCH" ]; then
|
|
199
|
-
output_skill "swarm" "$PROMPT" "$SWARM_MATCH"
|
|
200
|
-
exit 0
|
|
201
|
-
fi
|
|
202
|
-
if echo "$PROMPT_LOWER" | grep -qE '\bcoordinated\s+agents\b'; then
|
|
203
|
-
output_skill "swarm" "$PROMPT" "3"
|
|
204
|
-
exit 0
|
|
205
|
-
fi
|
|
206
|
-
|
|
207
|
-
# Priority 8: Pipeline
|
|
208
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(pipeline)\b' || \
|
|
209
|
-
echo "$PROMPT_LOWER" | grep -qE '\bchain\s+agents\b'; then
|
|
210
|
-
output_skill "pipeline" "$PROMPT"
|
|
211
|
-
exit 0
|
|
212
|
-
fi
|
|
213
|
-
|
|
214
|
-
# Priority 9: Ralplan keyword (before plan to avoid false match)
|
|
215
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(ralplan)\b'; then
|
|
216
|
-
output_skill "ralplan" "$PROMPT"
|
|
217
|
-
exit 0
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Priority 10: Plan keywords
|
|
221
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(plan this|plan the)\b'; then
|
|
222
|
-
output_skill "plan" "$PROMPT"
|
|
223
|
-
exit 0
|
|
224
|
-
fi
|
|
225
|
-
|
|
226
|
-
# Priority 11: TDD
|
|
227
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(tdd)\b' || \
|
|
228
|
-
echo "$PROMPT_LOWER" | grep -qE '\btest\s+first\b' || \
|
|
229
|
-
echo "$PROMPT_LOWER" | grep -qE '\bred\s+green\b'; then
|
|
230
|
-
output_skill "tdd" "$PROMPT"
|
|
231
|
-
exit 0
|
|
232
|
-
fi
|
|
233
|
-
|
|
234
|
-
# Priority 12: Research
|
|
235
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(research)\b' || \
|
|
236
|
-
echo "$PROMPT_LOWER" | grep -qE '\banalyze\s+data\b' || \
|
|
237
|
-
echo "$PROMPT_LOWER" | grep -qE '\bstatistics\b'; then
|
|
238
|
-
output_skill "research" "$PROMPT"
|
|
239
|
-
exit 0
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
# Priority 13: Ultrathink/think keywords (keep inline message)
|
|
243
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(ultrathink|think hard|think deeply)\b'; then
|
|
244
|
-
cat << 'EOF'
|
|
245
|
-
{"continue": true, "message": "<think-mode>\n\n**ULTRATHINK MODE ENABLED** - Extended reasoning activated.\n\nYou are now in deep thinking mode. Take your time to:\n1. Thoroughly analyze the problem from multiple angles\n2. Consider edge cases and potential issues\n3. Think through the implications of each approach\n4. Reason step-by-step before acting\n\nUse your extended thinking capabilities to provide the most thorough and well-reasoned response.\n\n</think-mode>\n\n---\n"}
|
|
246
|
-
EOF
|
|
247
|
-
exit 0
|
|
248
|
-
fi
|
|
249
|
-
|
|
250
|
-
# Priority 14: Deepsearch (RESTRICTED patterns)
|
|
251
|
-
if echo "$PROMPT_LOWER" | grep -qE '\b(deepsearch)\b' || \
|
|
252
|
-
echo "$PROMPT_LOWER" | grep -qE '\bsearch\s+(the\s+)?(codebase|code|files|project)\b' || \
|
|
253
|
-
echo "$PROMPT_LOWER" | grep -qE '\bfind\s+(in\s+)?(codebase|code|all\s+files)\b'; then
|
|
254
|
-
output_skill "deepsearch" "$PROMPT"
|
|
255
|
-
exit 0
|
|
256
|
-
fi
|
|
257
|
-
|
|
258
|
-
# Priority 15: Analyze (RESTRICTED patterns)
|
|
259
|
-
if echo "$PROMPT_LOWER" | grep -qE '\bdeep\s*analyze\b' || \
|
|
260
|
-
echo "$PROMPT_LOWER" | grep -qE '\binvestigate\s+(the|this|why)\b' || \
|
|
261
|
-
echo "$PROMPT_LOWER" | grep -qE '\bdebug\s+(the|this|why)\b'; then
|
|
262
|
-
output_skill "analyze" "$PROMPT"
|
|
263
|
-
exit 0
|
|
264
|
-
fi
|
|
265
|
-
|
|
266
|
-
# No keywords detected - continue without modification
|
|
267
|
-
echo '{"continue": true}'
|
|
268
|
-
exit 0
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# OMC Persistent Mode Hook
|
|
3
|
-
# Unified handler for ultrawork, ralph-loop, and todo continuation
|
|
4
|
-
# Prevents stopping when work remains incomplete
|
|
5
|
-
|
|
6
|
-
# Validate session ID to prevent path traversal attacks
|
|
7
|
-
# Returns 0 (success) for valid, 1 for invalid
|
|
8
|
-
is_valid_session_id() {
|
|
9
|
-
local id="$1"
|
|
10
|
-
if [ -z "$id" ]; then
|
|
11
|
-
return 1
|
|
12
|
-
fi
|
|
13
|
-
# Allow alphanumeric, hyphens, and underscores only
|
|
14
|
-
# Must not start with dot or hyphen, max 256 chars
|
|
15
|
-
if echo "$id" | grep -qE '^[a-zA-Z0-9][a-zA-Z0-9_-]{0,255}$'; then
|
|
16
|
-
return 0
|
|
17
|
-
fi
|
|
18
|
-
return 1
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
# Read stdin
|
|
22
|
-
INPUT=$(cat)
|
|
23
|
-
|
|
24
|
-
# Get session ID and directory
|
|
25
|
-
SESSION_ID=""
|
|
26
|
-
DIRECTORY=""
|
|
27
|
-
if command -v jq &> /dev/null; then
|
|
28
|
-
SESSION_ID=$(echo "$INPUT" | jq -r '.sessionId // .session_id // ""' 2>/dev/null)
|
|
29
|
-
DIRECTORY=$(echo "$INPUT" | jq -r '.directory // ""' 2>/dev/null)
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
# Default to current directory
|
|
33
|
-
if [ -z "$DIRECTORY" ]; then
|
|
34
|
-
DIRECTORY=$(pwd)
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
# Check for incomplete tasks in new Task system (priority over todos)
|
|
38
|
-
TASKS_DIR="$HOME/.claude/tasks"
|
|
39
|
-
TASK_COUNT=0
|
|
40
|
-
JQ_AVAILABLE=false
|
|
41
|
-
if command -v jq &> /dev/null; then
|
|
42
|
-
JQ_AVAILABLE=true
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
if [ -n "$SESSION_ID" ] && is_valid_session_id "$SESSION_ID" && [ -d "$TASKS_DIR/$SESSION_ID" ]; then
|
|
46
|
-
for task_file in "$TASKS_DIR/$SESSION_ID"/*.json; do
|
|
47
|
-
if [ -f "$task_file" ] && [ "$(basename "$task_file")" != ".lock" ]; then
|
|
48
|
-
if [ "$JQ_AVAILABLE" = "true" ]; then
|
|
49
|
-
STATUS=$(jq -r '.status // "pending"' "$task_file" 2>/dev/null)
|
|
50
|
-
# Match TypeScript isTaskIncomplete(): only pending/in_progress are incomplete
|
|
51
|
-
# 'deleted' and 'completed' are both treated as done
|
|
52
|
-
if [ "$STATUS" = "pending" ] || [ "$STATUS" = "in_progress" ]; then
|
|
53
|
-
TASK_COUNT=$((TASK_COUNT + 1))
|
|
54
|
-
fi
|
|
55
|
-
else
|
|
56
|
-
# Fallback: grep for incomplete status values (pending or in_progress)
|
|
57
|
-
# This is less accurate but provides basic functionality
|
|
58
|
-
if grep -qE '"status"[[:space:]]*:[[:space:]]*"(pending|in_progress)"' "$task_file" 2>/dev/null; then
|
|
59
|
-
TASK_COUNT=$((TASK_COUNT + 1))
|
|
60
|
-
fi
|
|
61
|
-
fi
|
|
62
|
-
fi
|
|
63
|
-
done
|
|
64
|
-
|
|
65
|
-
# Warn if using fallback (only once per invocation, to stderr)
|
|
66
|
-
if [ "$JQ_AVAILABLE" = "false" ] && [ "$TASK_COUNT" -gt 0 ]; then
|
|
67
|
-
echo "[OMC WARNING] jq not installed - Task counting may be less accurate. Install jq for best results." >&2
|
|
68
|
-
fi
|
|
69
|
-
fi
|
|
70
|
-
|
|
71
|
-
# Extract stop reason for abort detection
|
|
72
|
-
STOP_REASON=""
|
|
73
|
-
USER_REQUESTED=""
|
|
74
|
-
if command -v jq &> /dev/null; then
|
|
75
|
-
STOP_REASON=$(echo "$INPUT" | jq -r '.stop_reason // .stopReason // ""' 2>/dev/null)
|
|
76
|
-
USER_REQUESTED=$(echo "$INPUT" | jq -r '.user_requested // .userRequested // "false"' 2>/dev/null)
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# Check for user abort before continuation checks
|
|
80
|
-
# NOTE: Abort patterns are assumed - verify against actual Claude Code API values
|
|
81
|
-
if [ "$USER_REQUESTED" = "true" ] || echo "$STOP_REASON" | grep -qiE "(abort|cancel|interrupt|ctrl_c|manual_stop)"; then
|
|
82
|
-
echo '{"continue": true}'
|
|
83
|
-
exit 0
|
|
84
|
-
fi
|
|
85
|
-
|
|
86
|
-
# Check for active ultrawork state
|
|
87
|
-
ULTRAWORK_STATE=""
|
|
88
|
-
if [ -f "$DIRECTORY/.omc/state/ultrawork-state.json" ]; then
|
|
89
|
-
ULTRAWORK_STATE=$(cat "$DIRECTORY/.omc/state/ultrawork-state.json" 2>/dev/null)
|
|
90
|
-
elif [ -f "$HOME/.omc/state/ultrawork-state.json" ]; then
|
|
91
|
-
ULTRAWORK_STATE=$(cat "$HOME/.omc/state/ultrawork-state.json" 2>/dev/null)
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
# Check for active ralph loop
|
|
95
|
-
RALPH_STATE=""
|
|
96
|
-
if [ -f "$DIRECTORY/.omc/state/ralph-state.json" ]; then
|
|
97
|
-
RALPH_STATE=$(cat "$DIRECTORY/.omc/state/ralph-state.json" 2>/dev/null)
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
# Check for verification state (oracle verification)
|
|
101
|
-
VERIFICATION_STATE=""
|
|
102
|
-
if [ -f "$DIRECTORY/.omc/state/ralph-verification.json" ]; then
|
|
103
|
-
VERIFICATION_STATE=$(cat "$DIRECTORY/.omc/state/ralph-verification.json" 2>/dev/null)
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# Check for incomplete todos
|
|
107
|
-
INCOMPLETE_COUNT=0
|
|
108
|
-
TODOS_DIR="$HOME/.claude/todos"
|
|
109
|
-
if [ -d "$TODOS_DIR" ]; then
|
|
110
|
-
for todo_file in "$TODOS_DIR"/*.json; do
|
|
111
|
-
if [ -f "$todo_file" ]; then
|
|
112
|
-
if command -v jq &> /dev/null; then
|
|
113
|
-
COUNT=$(jq '[.[] | select(.status != "completed" and .status != "cancelled")] | length' "$todo_file" 2>/dev/null || echo "0")
|
|
114
|
-
INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
|
|
115
|
-
else
|
|
116
|
-
# Fallback: count "pending" or "in_progress" occurrences
|
|
117
|
-
COUNT=$(grep -c '"status"[[:space:]]*:[[:space:]]*"pending\|in_progress"' "$todo_file" 2>/dev/null) || COUNT=0
|
|
118
|
-
INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
|
|
119
|
-
fi
|
|
120
|
-
fi
|
|
121
|
-
done
|
|
122
|
-
fi
|
|
123
|
-
|
|
124
|
-
# Check project todos as well
|
|
125
|
-
for todo_path in "$DIRECTORY/.omc/todos.json" "$DIRECTORY/.claude/todos.json"; do
|
|
126
|
-
if [ -f "$todo_path" ]; then
|
|
127
|
-
if command -v jq &> /dev/null; then
|
|
128
|
-
COUNT=$(jq 'if type == "array" then [.[] | select(.status != "completed" and .status != "cancelled")] | length else 0 end' "$todo_path" 2>/dev/null || echo "0")
|
|
129
|
-
INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
|
|
130
|
-
else
|
|
131
|
-
# Fallback: count "pending" or "in_progress" occurrences
|
|
132
|
-
COUNT=$(grep -c '"status"[[:space:]]*:[[:space:]]*"pending\|in_progress"' "$todo_path" 2>/dev/null) || COUNT=0
|
|
133
|
-
INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
|
|
134
|
-
fi
|
|
135
|
-
fi
|
|
136
|
-
done
|
|
137
|
-
|
|
138
|
-
# Combine Task and todo counts
|
|
139
|
-
TOTAL_INCOMPLETE=$((TASK_COUNT + INCOMPLETE_COUNT))
|
|
140
|
-
|
|
141
|
-
# Priority 1: Ralph Loop with Oracle Verification
|
|
142
|
-
if [ -n "$RALPH_STATE" ]; then
|
|
143
|
-
IS_ACTIVE=$(echo "$RALPH_STATE" | jq -r '.active // false' 2>/dev/null)
|
|
144
|
-
if [ "$IS_ACTIVE" = "true" ]; then
|
|
145
|
-
ITERATION=$(echo "$RALPH_STATE" | jq -r '.iteration // 1' 2>/dev/null)
|
|
146
|
-
MAX_ITER=$(echo "$RALPH_STATE" | jq -r '.max_iterations // 10' 2>/dev/null)
|
|
147
|
-
PROMISE=$(echo "$RALPH_STATE" | jq -r '.completion_promise // "TASK_COMPLETE"' 2>/dev/null)
|
|
148
|
-
PROMPT=$(echo "$RALPH_STATE" | jq -r '.prompt // ""' 2>/dev/null)
|
|
149
|
-
|
|
150
|
-
# Check if oracle verification is pending
|
|
151
|
-
if [ -n "$VERIFICATION_STATE" ]; then
|
|
152
|
-
IS_PENDING=$(echo "$VERIFICATION_STATE" | jq -r '.pending // false' 2>/dev/null)
|
|
153
|
-
if [ "$IS_PENDING" = "true" ]; then
|
|
154
|
-
ATTEMPT=$(echo "$VERIFICATION_STATE" | jq -r '.verification_attempts // 0' 2>/dev/null)
|
|
155
|
-
MAX_ATTEMPTS=$(echo "$VERIFICATION_STATE" | jq -r '.max_verification_attempts // 3' 2>/dev/null)
|
|
156
|
-
ORIGINAL_TASK=$(echo "$VERIFICATION_STATE" | jq -r '.original_task // ""' 2>/dev/null)
|
|
157
|
-
COMPLETION_CLAIM=$(echo "$VERIFICATION_STATE" | jq -r '.completion_claim // ""' 2>/dev/null)
|
|
158
|
-
ORACLE_FEEDBACK=$(echo "$VERIFICATION_STATE" | jq -r '.oracle_feedback // ""' 2>/dev/null)
|
|
159
|
-
NEXT_ATTEMPT=$((ATTEMPT + 1))
|
|
160
|
-
|
|
161
|
-
FEEDBACK_SECTION=""
|
|
162
|
-
if [ -n "$ORACLE_FEEDBACK" ] && [ "$ORACLE_FEEDBACK" != "null" ]; then
|
|
163
|
-
FEEDBACK_SECTION="\\n**Previous Oracle Feedback (rejected):**\\n$ORACLE_FEEDBACK\\n"
|
|
164
|
-
fi
|
|
165
|
-
|
|
166
|
-
cat << EOF
|
|
167
|
-
{"continue": false, "reason": "<ralph-verification>\\n\\n[ORACLE VERIFICATION REQUIRED - Attempt $NEXT_ATTEMPT/$MAX_ATTEMPTS]\\n\\nThe agent claims the task is complete. Before accepting, YOU MUST verify with Oracle.\\n\\n**Original Task:**\\n$ORIGINAL_TASK\\n\\n**Completion Claim:**\\n$COMPLETION_CLAIM\\n$FEEDBACK_SECTION\\n## MANDATORY VERIFICATION STEPS\\n\\n1. **Spawn Oracle Agent** for verification:\\n \`\`\`\\n Task(subagent_type=\"oracle\", prompt=\"Verify this task completion claim...\")\\n \`\`\`\\n\\n2. **Oracle must check:**\\n - Are ALL requirements from the original task met?\\n - Is the implementation complete, not partial?\\n - Are there any obvious bugs or issues?\\n - Does the code compile/run without errors?\\n - Are tests passing (if applicable)?\\n\\n3. **Based on Oracle's response:**\\n - If APPROVED: Output \`<oracle-approved>VERIFIED_COMPLETE</oracle-approved>\`\\n - If REJECTED: Continue working on the identified issues\\n\\nDO NOT output the completion promise again until Oracle approves.\\n\\n</ralph-verification>\\n\\n---\\n"}
|
|
168
|
-
EOF
|
|
169
|
-
exit 0
|
|
170
|
-
fi
|
|
171
|
-
fi
|
|
172
|
-
|
|
173
|
-
if [ "$ITERATION" -lt "$MAX_ITER" ]; then
|
|
174
|
-
# Increment iteration
|
|
175
|
-
NEW_ITER=$((ITERATION + 1))
|
|
176
|
-
echo "$RALPH_STATE" | jq ".iteration = $NEW_ITER" > "$DIRECTORY/.omc/state/ralph-state.json" 2>/dev/null
|
|
177
|
-
|
|
178
|
-
cat << EOF
|
|
179
|
-
{"continue": false, "reason": "<ralph-loop-continuation>\\n\\n[RALPH LOOP - ITERATION $NEW_ITER/$MAX_ITER]\\n\\nYour previous attempt did not output the completion promise. The work is NOT done yet.\\n\\nCRITICAL INSTRUCTIONS:\\n1. Review your progress and the original task\\n2. Check your todo list - are ALL items marked complete?\\n3. Continue from where you left off\\n4. When FULLY complete, output: <promise>$PROMISE</promise>\\n5. Do NOT stop until the task is truly done\\n\\nOriginal task: $PROMPT\\n\\n</ralph-loop-continuation>\\n\\n---\\n"}
|
|
180
|
-
EOF
|
|
181
|
-
exit 0
|
|
182
|
-
fi
|
|
183
|
-
fi
|
|
184
|
-
fi
|
|
185
|
-
|
|
186
|
-
# Priority 2: Ultrawork Mode with incomplete todos
|
|
187
|
-
if [ -n "$ULTRAWORK_STATE" ] && [ "$TOTAL_INCOMPLETE" -gt 0 ]; then
|
|
188
|
-
# Check if active (with jq fallback)
|
|
189
|
-
IS_ACTIVE=""
|
|
190
|
-
if command -v jq &> /dev/null; then
|
|
191
|
-
IS_ACTIVE=$(echo "$ULTRAWORK_STATE" | jq -r '.active // false' 2>/dev/null)
|
|
192
|
-
else
|
|
193
|
-
# Fallback: grep for "active": true
|
|
194
|
-
if echo "$ULTRAWORK_STATE" | grep -q '"active"[[:space:]]*:[[:space:]]*true'; then
|
|
195
|
-
IS_ACTIVE="true"
|
|
196
|
-
fi
|
|
197
|
-
fi
|
|
198
|
-
|
|
199
|
-
if [ "$IS_ACTIVE" = "true" ]; then
|
|
200
|
-
# Get reinforcement count (with fallback)
|
|
201
|
-
REINFORCE_COUNT=0
|
|
202
|
-
if command -v jq &> /dev/null; then
|
|
203
|
-
REINFORCE_COUNT=$(echo "$ULTRAWORK_STATE" | jq -r '.reinforcement_count // 0' 2>/dev/null)
|
|
204
|
-
else
|
|
205
|
-
REINFORCE_COUNT=$(echo "$ULTRAWORK_STATE" | grep -oP '"reinforcement_count"[[:space:]]*:[[:space:]]*\K[0-9]+' 2>/dev/null) || REINFORCE_COUNT=0
|
|
206
|
-
fi
|
|
207
|
-
NEW_COUNT=$((REINFORCE_COUNT + 1))
|
|
208
|
-
|
|
209
|
-
# Get original prompt (with fallback)
|
|
210
|
-
ORIGINAL_PROMPT=""
|
|
211
|
-
if command -v jq &> /dev/null; then
|
|
212
|
-
ORIGINAL_PROMPT=$(echo "$ULTRAWORK_STATE" | jq -r '.original_prompt // ""' 2>/dev/null)
|
|
213
|
-
else
|
|
214
|
-
ORIGINAL_PROMPT=$(echo "$ULTRAWORK_STATE" | grep -oP '"original_prompt"[[:space:]]*:[[:space:]]*"\K[^"]+' 2>/dev/null) || ORIGINAL_PROMPT=""
|
|
215
|
-
fi
|
|
216
|
-
|
|
217
|
-
# Update state file (best effort)
|
|
218
|
-
if command -v jq &> /dev/null; then
|
|
219
|
-
echo "$ULTRAWORK_STATE" | jq ".reinforcement_count = $NEW_COUNT | .last_checked_at = \"$(date -Iseconds)\"" > "$DIRECTORY/.omc/state/ultrawork-state.json" 2>/dev/null
|
|
220
|
-
fi
|
|
221
|
-
|
|
222
|
-
cat << EOF
|
|
223
|
-
{"continue": false, "reason": "<ultrawork-persistence>\\n\\n[ULTRAWORK MODE STILL ACTIVE - Reinforcement #$NEW_COUNT]\\n\\nYour ultrawork session is NOT complete. $TOTAL_INCOMPLETE incomplete items remain.\\n\\nREMEMBER THE ULTRAWORK RULES:\\n- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially\\n- **BACKGROUND FIRST**: Use Task(run_in_background=true) for exploration (10+ concurrent)\\n- **TODO**: Track EVERY step. Mark complete IMMEDIATELY after each\\n- **VERIFY**: Check ALL requirements met before done\\n- **NO Premature Stopping**: ALL TODOs must be complete\\n\\nContinue working on the next pending item. DO NOT STOP until all items are marked complete.\\n\\nOriginal task: $ORIGINAL_PROMPT\\n\\n</ultrawork-persistence>\\n\\n---\\n"}
|
|
224
|
-
EOF
|
|
225
|
-
exit 0
|
|
226
|
-
fi
|
|
227
|
-
fi
|
|
228
|
-
|
|
229
|
-
# Priority 3: Todo/Task Continuation (baseline)
|
|
230
|
-
if [ "$TOTAL_INCOMPLETE" -gt 0 ]; then
|
|
231
|
-
if [ "$TASK_COUNT" -gt 0 ]; then
|
|
232
|
-
ITEM_TYPE="Tasks"
|
|
233
|
-
else
|
|
234
|
-
ITEM_TYPE="todos"
|
|
235
|
-
fi
|
|
236
|
-
cat << EOF
|
|
237
|
-
{"continue": false, "reason": "<todo-continuation>\\n\\n[SYSTEM REMINDER - CONTINUATION]\\n\\nIncomplete $ITEM_TYPE remain ($TOTAL_INCOMPLETE remaining). Continue working on the next pending item.\\n\\n- Proceed without asking for permission\\n- Mark each item complete when finished\\n- Do not stop until all items are done\\n\\n</todo-continuation>\\n\\n---\\n"}
|
|
238
|
-
EOF
|
|
239
|
-
exit 0
|
|
240
|
-
fi
|
|
241
|
-
|
|
242
|
-
# No blocking needed
|
|
243
|
-
echo '{"continue": true}'
|
|
244
|
-
exit 0
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# OMC Post-Tool-Use Hook
|
|
3
|
-
# Processes <remember> tags from Task agent output
|
|
4
|
-
# Saves to .omc/notepad.md for compaction-resilient memory
|
|
5
|
-
|
|
6
|
-
# Read stdin
|
|
7
|
-
INPUT=$(cat)
|
|
8
|
-
|
|
9
|
-
# Get directory and tool info
|
|
10
|
-
DIRECTORY=""
|
|
11
|
-
TOOL_NAME=""
|
|
12
|
-
TOOL_OUTPUT=""
|
|
13
|
-
if command -v jq &> /dev/null; then
|
|
14
|
-
DIRECTORY=$(echo "$INPUT" | jq -r '.directory // ""' 2>/dev/null)
|
|
15
|
-
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName // ""' 2>/dev/null)
|
|
16
|
-
TOOL_OUTPUT=$(echo "$INPUT" | jq -r '.toolOutput // ""' 2>/dev/null)
|
|
17
|
-
else
|
|
18
|
-
# Fallback: use grep/sed for extraction
|
|
19
|
-
DIRECTORY=$(echo "$INPUT" | grep -oP '"directory"\s*:\s*"\K[^"]+' | head -1)
|
|
20
|
-
TOOL_NAME=$(echo "$INPUT" | grep -oP '"toolName"\s*:\s*"\K[^"]+' | head -1)
|
|
21
|
-
TOOL_OUTPUT=$(echo "$INPUT" | grep -oP '"toolOutput"\s*:\s*"\K[^"]+' | head -1)
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
if [ -z "$DIRECTORY" ]; then
|
|
25
|
-
DIRECTORY=$(pwd)
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
# Only process Task tool output
|
|
29
|
-
if [ "$TOOL_NAME" != "Task" ] && [ "$TOOL_NAME" != "task" ]; then
|
|
30
|
-
echo '{"continue": true}'
|
|
31
|
-
exit 0
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
# Check for <remember> tags
|
|
35
|
-
if ! echo "$TOOL_OUTPUT" | grep -q '<remember'; then
|
|
36
|
-
echo '{"continue": true}'
|
|
37
|
-
exit 0
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
# Create .omc directory if needed
|
|
41
|
-
OMC_DIR="$DIRECTORY/.omc"
|
|
42
|
-
NOTEPAD_FILE="$OMC_DIR/notepad.md"
|
|
43
|
-
mkdir -p "$OMC_DIR" 2>/dev/null
|
|
44
|
-
|
|
45
|
-
# Initialize notepad.md if it doesn't exist
|
|
46
|
-
if [ ! -f "$NOTEPAD_FILE" ]; then
|
|
47
|
-
cat > "$NOTEPAD_FILE" << 'NOTEPAD_INIT'
|
|
48
|
-
# Notepad
|
|
49
|
-
<!-- Auto-managed by OMC. Manual edits preserved in MANUAL section. -->
|
|
50
|
-
|
|
51
|
-
## Priority Context
|
|
52
|
-
<!-- ALWAYS loaded. Keep under 500 chars. Critical discoveries only. -->
|
|
53
|
-
|
|
54
|
-
## Working Memory
|
|
55
|
-
<!-- Session notes. Auto-pruned after 7 days. -->
|
|
56
|
-
|
|
57
|
-
## MANUAL
|
|
58
|
-
<!-- User content. Never auto-pruned. -->
|
|
59
|
-
NOTEPAD_INIT
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
# Process priority remember tags
|
|
63
|
-
PRIORITY_CONTENT=$(echo "$TOOL_OUTPUT" | grep -oP '<remember\s+priority>\K[\s\S]*?(?=</remember>)' | head -1)
|
|
64
|
-
if [ -n "$PRIORITY_CONTENT" ]; then
|
|
65
|
-
# Read current notepad
|
|
66
|
-
NOTEPAD_CONTENT=$(cat "$NOTEPAD_FILE")
|
|
67
|
-
# Replace Priority Context section
|
|
68
|
-
NEW_NOTEPAD=$(echo "$NOTEPAD_CONTENT" | sed '/## Priority Context/,/## Working Memory/{
|
|
69
|
-
/## Priority Context/!{/## Working Memory/!d}
|
|
70
|
-
}' | sed "/## Priority Context/a\\<!-- ALWAYS loaded. Keep under 500 chars. Critical discoveries only. -->\\n$PRIORITY_CONTENT")
|
|
71
|
-
echo "$NEW_NOTEPAD" > "$NOTEPAD_FILE"
|
|
72
|
-
fi
|
|
73
|
-
|
|
74
|
-
# Process regular remember tags
|
|
75
|
-
while IFS= read -r CONTENT; do
|
|
76
|
-
if [ -n "$CONTENT" ]; then
|
|
77
|
-
TIMESTAMP=$(date '+%Y-%m-%d %H:%M')
|
|
78
|
-
# Append to Working Memory section (before MANUAL)
|
|
79
|
-
sed -i "/## MANUAL/i\\### $TIMESTAMP\\n$CONTENT\\n" "$NOTEPAD_FILE" 2>/dev/null || {
|
|
80
|
-
# macOS sed fallback
|
|
81
|
-
sed -i '' "/## MANUAL/i\\
|
|
82
|
-
### $TIMESTAMP\\
|
|
83
|
-
$CONTENT\\
|
|
84
|
-
" "$NOTEPAD_FILE"
|
|
85
|
-
}
|
|
86
|
-
fi
|
|
87
|
-
done < <(echo "$TOOL_OUTPUT" | grep -oP '<remember>\K[\s\S]*?(?=</remember>)')
|
|
88
|
-
|
|
89
|
-
echo '{"continue": true}'
|
|
90
|
-
exit 0
|