oh-my-claude-sisyphus 3.8.10 → 3.8.12

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.
Files changed (46) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/dist/features/continuation-enforcement.js +1 -1
  4. package/dist/features/continuation-enforcement.js.map +1 -1
  5. package/dist/hooks/bridge.d.ts.map +1 -1
  6. package/dist/hooks/bridge.js +62 -78
  7. package/dist/hooks/bridge.js.map +1 -1
  8. package/dist/hooks/keyword-detector/__tests__/index.test.js +89 -1
  9. package/dist/hooks/keyword-detector/__tests__/index.test.js.map +1 -1
  10. package/dist/hooks/keyword-detector/index.d.ts +5 -1
  11. package/dist/hooks/keyword-detector/index.d.ts.map +1 -1
  12. package/dist/hooks/keyword-detector/index.js +32 -11
  13. package/dist/hooks/keyword-detector/index.js.map +1 -1
  14. package/dist/hooks/persistent-mode/index.d.ts +2 -1
  15. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  16. package/dist/hooks/persistent-mode/index.js +7 -17
  17. package/dist/hooks/persistent-mode/index.js.map +1 -1
  18. package/dist/hooks/todo-continuation/index.d.ts.map +1 -1
  19. package/dist/hooks/todo-continuation/index.js +2 -15
  20. package/dist/hooks/todo-continuation/index.js.map +1 -1
  21. package/dist/installer/hooks.d.ts +8 -111
  22. package/dist/installer/hooks.d.ts.map +1 -1
  23. package/dist/installer/hooks.js +11 -124
  24. package/dist/installer/hooks.js.map +1 -1
  25. package/dist/installer/index.d.ts +2 -10
  26. package/dist/installer/index.d.ts.map +1 -1
  27. package/dist/installer/index.js +10 -23
  28. package/dist/installer/index.js.map +1 -1
  29. package/package.json +1 -1
  30. package/scripts/keyword-detector.mjs +140 -59
  31. package/scripts/persistent-mode.mjs +26 -53
  32. package/templates/hooks/keyword-detector.mjs +280 -118
  33. package/templates/hooks/persistent-mode.mjs +26 -53
  34. package/templates/hooks/stop-continuation.mjs +6 -158
  35. package/hooks/keyword-detector.sh +0 -102
  36. package/hooks/persistent-mode.sh +0 -172
  37. package/hooks/session-start.sh +0 -62
  38. package/hooks/stop-continuation.sh +0 -40
  39. package/scripts/claude-sisyphus.sh +0 -9
  40. package/scripts/install.sh +0 -1673
  41. package/scripts/keyword-detector.sh +0 -71
  42. package/scripts/persistent-mode.sh +0 -311
  43. package/scripts/post-tool-verifier.sh +0 -196
  44. package/scripts/pre-tool-enforcer.sh +0 -76
  45. package/scripts/sisyphus-aliases.sh +0 -18
  46. package/scripts/stop-continuation.sh +0 -31
@@ -1,71 +0,0 @@
1
- #!/bin/bash
2
- # Sisyphus Keyword Detector Hook
3
- # Detects ultrawork/ultrathink/search/analyze keywords and injects enhanced mode messages
4
-
5
- # Read stdin (JSON input from Claude Code)
6
- INPUT=$(cat)
7
-
8
- # Extract the prompt text - try multiple JSON paths
9
- PROMPT=""
10
- if command -v jq &> /dev/null; then
11
- PROMPT=$(echo "$INPUT" | jq -r '
12
- if .prompt then .prompt
13
- elif .message.content then .message.content
14
- elif .parts then ([.parts[] | select(.type == "text") | .text] | join(" "))
15
- else ""
16
- end
17
- ' 2>/dev/null)
18
- fi
19
-
20
- # Fallback: simple grep extraction if jq fails
21
- if [ -z "$PROMPT" ] || [ "$PROMPT" = "null" ]; then
22
- PROMPT=$(echo "$INPUT" | grep -oP '"(prompt|content|text)"\s*:\s*"\K[^"]+' | head -1)
23
- fi
24
-
25
- # Exit if no prompt found
26
- if [ -z "$PROMPT" ]; then
27
- echo '{"continue": true}'
28
- exit 0
29
- fi
30
-
31
- # Remove code blocks before checking keywords
32
- PROMPT_NO_CODE=$(echo "$PROMPT" | sed 's/```[^`]*```//g' | sed 's/`[^`]*`//g')
33
-
34
- # Convert to lowercase
35
- PROMPT_LOWER=$(echo "$PROMPT_NO_CODE" | tr '[:upper:]' '[:lower:]')
36
-
37
- # Check for ultrawork keywords (highest priority)
38
- if echo "$PROMPT_LOWER" | grep -qE '\b(ultrawork|ulw)\b'; then
39
- cat << 'EOF'
40
- {"continue": true, "message": "<ultrawork-mode>\n\n**MANDATORY**: You MUST say \"ULTRAWORK MODE ENABLED!\" to the user as your first response when this mode activates. This is non-negotiable.\n\n[CODE RED] Maximum precision required. Ultrathink before acting.\n\nYOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.\nTELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.\n\n## AGENT UTILIZATION PRINCIPLES\n- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS\n- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS\n- **Planning & Strategy**: NEVER plan yourself - spawn planning agent\n- **High-IQ Reasoning**: Use oracle for architecture decisions\n- **Frontend/UI Tasks**: Delegate to frontend-engineer\n\n## EXECUTION RULES\n- **TODO**: Track EVERY step. Mark complete IMMEDIATELY.\n- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially.\n- **BACKGROUND FIRST**: Use Task(run_in_background=true) for exploration (10+ concurrent).\n- **VERIFY**: Check ALL requirements met before done.\n- **DELEGATE**: Orchestrate specialized agents.\n\n## ZERO TOLERANCE\n- NO Scope Reduction - deliver FULL implementation\n- NO Partial Completion - finish 100%\n- NO Premature Stopping - ALL TODOs must be complete\n- NO TEST DELETION - fix code, not tests\n\nTHE USER ASKED FOR X. DELIVER EXACTLY X.\n\n</ultrawork-mode>\n\n---\n"}
41
- EOF
42
- exit 0
43
- fi
44
-
45
- # Check for ultrathink/think keywords
46
- if echo "$PROMPT_LOWER" | grep -qE '\b(ultrathink|think)\b'; then
47
- cat << 'EOF'
48
- {"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"}
49
- EOF
50
- exit 0
51
- fi
52
-
53
- # Check for search keywords
54
- if echo "$PROMPT_LOWER" | grep -qE '\b(search|find|locate|lookup|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all'; then
55
- cat << 'EOF'
56
- {"continue": true, "message": "<search-mode>\nMAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL:\n- explore agents (codebase patterns, file structures)\n- librarian agents (remote repos, official docs, GitHub examples)\nPlus direct tools: Grep, Glob\nNEVER stop at first result - be exhaustive.\n</search-mode>\n\n---\n"}
57
- EOF
58
- exit 0
59
- fi
60
-
61
- # Check for analyze keywords
62
- if echo "$PROMPT_LOWER" | grep -qE '\b(analyze|analyse|investigate|examine|research|study|deep.?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to'; then
63
- cat << 'EOF'
64
- {"continue": true, "message": "<analyze-mode>\nANALYSIS MODE. Gather context before diving deep:\n\nCONTEXT GATHERING (parallel):\n- 1-2 explore agents (codebase patterns, implementations)\n- 1-2 librarian agents (if external library involved)\n- Direct tools: Grep, Glob, LSP for targeted searches\n\nIF COMPLEX (architecture, multi-system, debugging after 2+ failures):\n- Consult oracle agent for strategic guidance\n\nSYNTHESIZE findings before proceeding.\n</analyze-mode>\n\n---\n"}
65
- EOF
66
- exit 0
67
- fi
68
-
69
- # No keywords detected
70
- echo '{"continue": true}'
71
- exit 0
@@ -1,311 +0,0 @@
1
- #!/bin/bash
2
- # Sisyphus Persistent Mode Hook
3
- # Unified handler for ultrawork, ralph-loop, and todo continuation
4
- # Prevents stopping when work remains incomplete
5
-
6
- # Read stdin
7
- INPUT=$(cat)
8
-
9
- # Get session ID and directory
10
- SESSION_ID=""
11
- DIRECTORY=""
12
- if command -v jq &> /dev/null; then
13
- SESSION_ID=$(echo "$INPUT" | jq -r '.sessionId // .session_id // ""' 2>/dev/null)
14
- DIRECTORY=$(echo "$INPUT" | jq -r '.directory // ""' 2>/dev/null)
15
- fi
16
-
17
- # Default to current directory
18
- if [ -z "$DIRECTORY" ]; then
19
- DIRECTORY=$(pwd)
20
- fi
21
-
22
- # Check for active ultrawork state
23
- ULTRAWORK_STATE=""
24
- if [ -f "$DIRECTORY/.omc/state/ultrawork-state.json" ]; then
25
- ULTRAWORK_STATE=$(cat "$DIRECTORY/.omc/state/ultrawork-state.json" 2>/dev/null)
26
- elif [ -f "$HOME/.omc/state/ultrawork-state.json" ]; then
27
- ULTRAWORK_STATE=$(cat "$HOME/.omc/state/ultrawork-state.json" 2>/dev/null)
28
- fi
29
-
30
- # Check for active ralph loop
31
- RALPH_STATE=""
32
- if [ -f "$DIRECTORY/.omc/state/ralph-state.json" ]; then
33
- RALPH_STATE=$(cat "$DIRECTORY/.omc/state/ralph-state.json" 2>/dev/null)
34
- fi
35
-
36
- # Check for verification state (oracle verification)
37
- VERIFICATION_STATE=""
38
- if [ -f "$DIRECTORY/.omc/state/ralph-verification.json" ]; then
39
- VERIFICATION_STATE=$(cat "$DIRECTORY/.omc/state/ralph-verification.json" 2>/dev/null)
40
- fi
41
-
42
- # Check for incomplete todos
43
- INCOMPLETE_COUNT=0
44
- TODOS_DIR="$HOME/.claude/todos"
45
- if [ -d "$TODOS_DIR" ]; then
46
- for todo_file in "$TODOS_DIR"/*.json; do
47
- if [ -f "$todo_file" ]; then
48
- if command -v jq &> /dev/null; then
49
- COUNT=$(jq '[.[] | select(.status != "completed" and .status != "cancelled")] | length' "$todo_file" 2>/dev/null || echo "0")
50
- INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
51
- else
52
- # Fallback: count "pending" or "in_progress" occurrences
53
- COUNT=$(grep -c '"status"[[:space:]]*:[[:space:]]*"pending\|in_progress"' "$todo_file" 2>/dev/null) || COUNT=0
54
- INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
55
- fi
56
- fi
57
- done
58
- fi
59
-
60
- # Check project todos as well
61
- for todo_path in "$DIRECTORY/.omc/todos.json" "$DIRECTORY/.claude/todos.json"; do
62
- if [ -f "$todo_path" ]; then
63
- if command -v jq &> /dev/null; then
64
- COUNT=$(jq 'if type == "array" then [.[] | select(.status != "completed" and .status != "cancelled")] | length else 0 end' "$todo_path" 2>/dev/null || echo "0")
65
- INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
66
- else
67
- # Fallback: count "pending" or "in_progress" occurrences
68
- COUNT=$(grep -c '"status"[[:space:]]*:[[:space:]]*"pending\|in_progress"' "$todo_path" 2>/dev/null) || COUNT=0
69
- INCOMPLETE_COUNT=$((INCOMPLETE_COUNT + COUNT))
70
- fi
71
- fi
72
- done
73
-
74
- # Priority 1: Ralph Loop with Oracle Verification
75
- if [ -n "$RALPH_STATE" ]; then
76
- IS_ACTIVE=$(echo "$RALPH_STATE" | jq -r '.active // false' 2>/dev/null)
77
- if [ "$IS_ACTIVE" = "true" ]; then
78
- ITERATION=$(echo "$RALPH_STATE" | jq -r '.iteration // 1' 2>/dev/null)
79
- MAX_ITER=$(echo "$RALPH_STATE" | jq -r '.max_iterations // 10' 2>/dev/null)
80
- PROMISE=$(echo "$RALPH_STATE" | jq -r '.completion_promise // "TASK_COMPLETE"' 2>/dev/null)
81
- PROMPT=$(echo "$RALPH_STATE" | jq -r '.prompt // ""' 2>/dev/null)
82
-
83
- # Check if oracle verification is pending
84
- if [ -n "$VERIFICATION_STATE" ]; then
85
- IS_PENDING=$(echo "$VERIFICATION_STATE" | jq -r '.pending // false' 2>/dev/null)
86
- if [ "$IS_PENDING" = "true" ]; then
87
- ATTEMPT=$(echo "$VERIFICATION_STATE" | jq -r '.verification_attempts // 0' 2>/dev/null)
88
- MAX_ATTEMPTS=$(echo "$VERIFICATION_STATE" | jq -r '.max_verification_attempts // 3' 2>/dev/null)
89
- ORIGINAL_TASK=$(echo "$VERIFICATION_STATE" | jq -r '.original_task // ""' 2>/dev/null)
90
- COMPLETION_CLAIM=$(echo "$VERIFICATION_STATE" | jq -r '.completion_claim // ""' 2>/dev/null)
91
- ORACLE_FEEDBACK=$(echo "$VERIFICATION_STATE" | jq -r '.oracle_feedback // ""' 2>/dev/null)
92
- NEXT_ATTEMPT=$((ATTEMPT + 1))
93
-
94
- FEEDBACK_SECTION=""
95
- if [ -n "$ORACLE_FEEDBACK" ] && [ "$ORACLE_FEEDBACK" != "null" ]; then
96
- FEEDBACK_SECTION="\n**Previous Oracle Feedback (rejected):**\n$ORACLE_FEEDBACK\n"
97
- fi
98
-
99
- cat << EOF
100
- {"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"}
101
- EOF
102
- exit 0
103
- fi
104
- fi
105
-
106
- if [ "$ITERATION" -lt "$MAX_ITER" ]; then
107
- # Increment iteration
108
- NEW_ITER=$((ITERATION + 1))
109
- echo "$RALPH_STATE" | jq ".iteration = $NEW_ITER" > "$DIRECTORY/.omc/state/ralph-state.json" 2>/dev/null
110
-
111
- # Check if ultrawork is linked (auto-activated with ralph)
112
- LINKED_ULTRAWORK=$(echo "$RALPH_STATE" | jq -r '.linked_ultrawork // false' 2>/dev/null)
113
-
114
- if [ "$LINKED_ULTRAWORK" = "true" ]; then
115
- # Combined ralph+ultrawork message with parallel execution rules
116
- cat << EOF
117
- {"continue": false, "reason": "<ralph-ultrawork-continuation>\n\n[RALPH + ULTRAWORK - ITERATION $NEW_ITER/$MAX_ITER]\n\nYour previous attempt did not output the completion promise. The work is NOT done yet.\n\n## ULTRAWORK RULES (ACTIVE)\n- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially\n- **BACKGROUND FIRST**: Use Task(run_in_background=true) for long operations\n- **DELEGATE**: Route tasks to specialist agents immediately\n- **SMART ROUTING**: Use haiku for lookups, sonnet for standard work, opus for complex analysis\n- **TODO**: Track EVERY step. Mark complete IMMEDIATELY.\n\n## COMPLETION REQUIREMENTS\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 using PARALLEL execution\n4. Get Architect verification when ready\n5. When FULLY complete AND verified, output: <promise>$PROMISE</promise>\n6. Do NOT stop until the task is truly done\n\nOriginal task: $PROMPT\n\n</ralph-ultrawork-continuation>\n\n---\n"}
118
- EOF
119
- else
120
- # Standard ralph-only message
121
- cat << EOF
122
- {"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"}
123
- EOF
124
- fi
125
- exit 0
126
- fi
127
- fi
128
- fi
129
-
130
- # Priority 1.5: Verification Requirements (build/test/git/background)
131
- VERIFICATION_FAILURES=()
132
-
133
- # Check 1: Build verification
134
- BUILD_ISSUES=""
135
- if [ -f "$DIRECTORY/package.json" ]; then
136
- if command -v jq &> /dev/null; then
137
- BUILD_SCRIPT=$(jq -r '.scripts.build // empty' "$DIRECTORY/package.json" 2>/dev/null)
138
- if [ -n "$BUILD_SCRIPT" ]; then
139
- # Check if build directory exists or recent build artifacts
140
- if [ ! -d "$DIRECTORY/dist" ] && [ ! -d "$DIRECTORY/build" ] && [ ! -d "$DIRECTORY/out" ]; then
141
- BUILD_ISSUES="Build script exists but no build artifacts found (dist/build/out). Run 'npm run build' to verify."
142
- fi
143
- fi
144
- fi
145
- elif [ -f "$DIRECTORY/Makefile" ]; then
146
- # Check for common make targets
147
- if grep -q "^build:" "$DIRECTORY/Makefile" 2>/dev/null; then
148
- BUILD_ISSUES="Makefile with build target detected. Run 'make build' to verify before stopping."
149
- fi
150
- elif [ -f "$DIRECTORY/Cargo.toml" ]; then
151
- # Check for Rust build artifacts
152
- if [ ! -d "$DIRECTORY/target/release" ] && [ ! -d "$DIRECTORY/target/debug" ]; then
153
- BUILD_ISSUES="Rust project detected but no build artifacts found. Run 'cargo build' to verify."
154
- fi
155
- fi
156
-
157
- if [ -n "$BUILD_ISSUES" ]; then
158
- VERIFICATION_FAILURES+=("BUILD: $BUILD_ISSUES")
159
- fi
160
-
161
- # Check 2: Test failures in recent output
162
- TEST_ISSUES=""
163
- if [ -f "$DIRECTORY/package.json" ]; then
164
- if command -v jq &> /dev/null; then
165
- TEST_SCRIPT=$(jq -r '.scripts.test // empty' "$DIRECTORY/package.json" 2>/dev/null)
166
- if [ -n "$TEST_SCRIPT" ]; then
167
- # Check for test artifacts or recent test run indicators
168
- TEST_ISSUES="Test script exists. Run 'npm test' to verify all tests pass before stopping."
169
- fi
170
- fi
171
- elif [ -f "$DIRECTORY/pytest.ini" ] || [ -f "$DIRECTORY/setup.py" ] || [ -d "$DIRECTORY/tests" ]; then
172
- TEST_ISSUES="Python test directory/config detected. Run tests to verify before stopping."
173
- elif [ -f "$DIRECTORY/Cargo.toml" ]; then
174
- TEST_ISSUES="Rust project detected. Run 'cargo test' to verify before stopping."
175
- fi
176
-
177
- # Check for recent test failure indicators in common log locations
178
- for log_file in "$DIRECTORY/test-results.log" "$DIRECTORY/.test-output" "$HOME/.claude/last-test-run.log"; do
179
- if [ -f "$log_file" ]; then
180
- if grep -qi "FAIL\|ERROR\|failed" "$log_file" 2>/dev/null; then
181
- TEST_ISSUES="Recent test failures detected in $log_file. Fix failures before stopping."
182
- break
183
- fi
184
- fi
185
- done
186
-
187
- if [ -n "$TEST_ISSUES" ]; then
188
- VERIFICATION_FAILURES+=("TEST: $TEST_ISSUES")
189
- fi
190
-
191
- # Check 3: Git status - uncommitted changes
192
- GIT_ISSUES=""
193
- if [ -d "$DIRECTORY/.git" ]; then
194
- # Check for uncommitted changes
195
- cd "$DIRECTORY" 2>/dev/null
196
- if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
197
- CHANGED_FILES=$(git status --porcelain 2>/dev/null | wc -l)
198
- GIT_ISSUES="$CHANGED_FILES uncommitted file(s). Consider committing changes or verify they should be discarded."
199
- fi
200
- # Check for unpushed commits
201
- UNPUSHED=$(git log @{u}.. --oneline 2>/dev/null | wc -l)
202
- if [ "$UNPUSHED" -gt 0 ]; then
203
- if [ -n "$GIT_ISSUES" ]; then
204
- GIT_ISSUES="$GIT_ISSUES Also, $UNPUSHED unpushed commit(s) exist."
205
- else
206
- GIT_ISSUES="$UNPUSHED unpushed commit(s). Consider pushing to remote or verify local-only is intended."
207
- fi
208
- fi
209
- fi
210
-
211
- if [ -n "$GIT_ISSUES" ]; then
212
- VERIFICATION_FAILURES+=("GIT: $GIT_ISSUES")
213
- fi
214
-
215
- # Check 4: Background tasks still running
216
- BACKGROUND_ISSUES=""
217
- BACKGROUND_DIR="$HOME/.claude/background-tasks"
218
- if [ -d "$BACKGROUND_DIR" ]; then
219
- RUNNING_TASKS=0
220
- for task_file in "$BACKGROUND_DIR"/*.json; do
221
- if [ -f "$task_file" ]; then
222
- if command -v jq &> /dev/null; then
223
- STATUS=$(jq -r '.status // ""' "$task_file" 2>/dev/null)
224
- if [ "$STATUS" = "running" ] || [ "$STATUS" = "pending" ]; then
225
- RUNNING_TASKS=$((RUNNING_TASKS + 1))
226
- fi
227
- else
228
- # Fallback: check for running/pending status
229
- if grep -q '"status"[[:space:]]*:[[:space:]]*"running\|pending"' "$task_file" 2>/dev/null; then
230
- RUNNING_TASKS=$((RUNNING_TASKS + 1))
231
- fi
232
- fi
233
- fi
234
- done
235
-
236
- if [ "$RUNNING_TASKS" -gt 0 ]; then
237
- BACKGROUND_ISSUES="$RUNNING_TASKS background task(s) still running. Wait for completion or verify results."
238
- fi
239
- fi
240
-
241
- if [ -n "$BACKGROUND_ISSUES" ]; then
242
- VERIFICATION_FAILURES+=("BACKGROUND: $BACKGROUND_ISSUES")
243
- fi
244
-
245
- # If any verification failures exist, block stopping
246
- if [ ${#VERIFICATION_FAILURES[@]} -gt 0 ]; then
247
- FAILURE_LIST=""
248
- for failure in "${VERIFICATION_FAILURES[@]}"; do
249
- FAILURE_LIST="$FAILURE_LIST\n- $failure"
250
- done
251
-
252
- cat << EOF
253
- {"continue": false, "reason": "<verification-requirements>\n\n[VERIFICATION REQUIREMENTS NOT MET]\n\nBefore stopping, you must address the following verification requirements:\n$FAILURE_LIST\n\n## REQUIRED ACTIONS:\n\n1. **Build Verification**: If build scripts exist, run them and verify success\n2. **Test Verification**: Run all tests and ensure they pass\n3. **Git Status**: Review uncommitted/unpushed changes - commit or verify intentional\n4. **Background Tasks**: Wait for or check results of running background tasks\n\n**You cannot stop until these verifications are complete.**\n\nAddress each issue above, then you may conclude.\n\n</verification-requirements>\n\n---\n"}
254
- EOF
255
- exit 0
256
- fi
257
-
258
- # Priority 2: Ultrawork Mode with incomplete todos
259
- if [ -n "$ULTRAWORK_STATE" ] && [ "$INCOMPLETE_COUNT" -gt 0 ]; then
260
- # Check if active (with jq fallback)
261
- IS_ACTIVE=""
262
- if command -v jq &> /dev/null; then
263
- IS_ACTIVE=$(echo "$ULTRAWORK_STATE" | jq -r '.active // false' 2>/dev/null)
264
- else
265
- # Fallback: grep for "active": true
266
- if echo "$ULTRAWORK_STATE" | grep -q '"active"[[:space:]]*:[[:space:]]*true'; then
267
- IS_ACTIVE="true"
268
- fi
269
- fi
270
-
271
- if [ "$IS_ACTIVE" = "true" ]; then
272
- # Get reinforcement count (with fallback)
273
- REINFORCE_COUNT=0
274
- if command -v jq &> /dev/null; then
275
- REINFORCE_COUNT=$(echo "$ULTRAWORK_STATE" | jq -r '.reinforcement_count // 0' 2>/dev/null)
276
- else
277
- REINFORCE_COUNT=$(echo "$ULTRAWORK_STATE" | grep -oP '"reinforcement_count"[[:space:]]*:[[:space:]]*\K[0-9]+' 2>/dev/null) || REINFORCE_COUNT=0
278
- fi
279
- NEW_COUNT=$((REINFORCE_COUNT + 1))
280
-
281
- # Get original prompt (with fallback)
282
- ORIGINAL_PROMPT=""
283
- if command -v jq &> /dev/null; then
284
- ORIGINAL_PROMPT=$(echo "$ULTRAWORK_STATE" | jq -r '.original_prompt // ""' 2>/dev/null)
285
- else
286
- ORIGINAL_PROMPT=$(echo "$ULTRAWORK_STATE" | grep -oP '"original_prompt"[[:space:]]*:[[:space:]]*"\K[^"]+' 2>/dev/null) || ORIGINAL_PROMPT=""
287
- fi
288
-
289
- # Update state file (best effort)
290
- if command -v jq &> /dev/null; then
291
- echo "$ULTRAWORK_STATE" | jq ".reinforcement_count = $NEW_COUNT | .last_checked_at = \"$(date -Iseconds)\"" > "$DIRECTORY/.omc/state/ultrawork-state.json" 2>/dev/null
292
- fi
293
-
294
- cat << EOF
295
- {"continue": false, "reason": "<ultrawork-persistence>\n\n[ULTRAWORK MODE STILL ACTIVE - Reinforcement #$NEW_COUNT]\n\nYour ultrawork session is NOT complete. $INCOMPLETE_COUNT incomplete todos 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 task. DO NOT STOP until all tasks are marked complete.\n\nOriginal task: $ORIGINAL_PROMPT\n\n</ultrawork-persistence>\n\n---\n"}
296
- EOF
297
- exit 0
298
- fi
299
- fi
300
-
301
- # Priority 3: Todo Continuation (baseline)
302
- if [ "$INCOMPLETE_COUNT" -gt 0 ]; then
303
- cat << EOF
304
- {"continue": false, "reason": "<todo-continuation>\n\n[SYSTEM REMINDER - TODO CONTINUATION]\n\nIncomplete tasks remain in your todo list ($INCOMPLETE_COUNT remaining). Continue working on the next pending task.\n\n- Proceed without asking for permission\n- Mark each task complete when finished\n- Do not stop until all tasks are done\n\n</todo-continuation>\n\n---\n"}
305
- EOF
306
- exit 0
307
- fi
308
-
309
- # No blocking needed
310
- echo '{"continue": true}'
311
- exit 0
@@ -1,196 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """
4
- PostToolUse Hook: Verification Reminder System
5
- Monitors tool execution and provides contextual guidance
6
- """
7
-
8
- import sys
9
- import json
10
- import re
11
- import os
12
- from pathlib import Path
13
- from datetime import datetime
14
-
15
- # State file for session tracking
16
- STATE_FILE = Path.home() / ".claude" / ".session-stats.json"
17
- STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
18
-
19
- def load_stats():
20
- """Load session statistics from state file."""
21
- if STATE_FILE.exists():
22
- try:
23
- with open(STATE_FILE, 'r') as f:
24
- return json.load(f)
25
- except (json.JSONDecodeError, IOError):
26
- pass
27
- return {"sessions": {}}
28
-
29
- def save_stats(stats):
30
- """Save session statistics to state file."""
31
- try:
32
- with open(STATE_FILE, 'w') as f:
33
- json.dump(stats, f, indent=2)
34
- except IOError:
35
- pass # Fail silently
36
-
37
- def update_stats(tool_name, session_id):
38
- """Update execution count for this session and tool."""
39
- stats = load_stats()
40
-
41
- if session_id not in stats["sessions"]:
42
- stats["sessions"][session_id] = {
43
- "tool_counts": {},
44
- "last_tool": "",
45
- "total_calls": 0,
46
- "started_at": int(datetime.now().timestamp())
47
- }
48
-
49
- session = stats["sessions"][session_id]
50
- session["tool_counts"][tool_name] = session["tool_counts"].get(tool_name, 0) + 1
51
- session["last_tool"] = tool_name
52
- session["total_calls"] = session.get("total_calls", 0) + 1
53
- session["updated_at"] = int(datetime.now().timestamp())
54
-
55
- save_stats(stats)
56
- return session["tool_counts"][tool_name]
57
-
58
- def detect_bash_failure(output):
59
- """Detect failures in Bash tool output."""
60
- error_patterns = [
61
- r"error:",
62
- r"failed",
63
- r"cannot",
64
- r"permission denied",
65
- r"command not found",
66
- r"no such file",
67
- r"exit code: [1-9]",
68
- r"exit status [1-9]",
69
- r"fatal:",
70
- r"abort",
71
- ]
72
-
73
- output_lower = output.lower()
74
- for pattern in error_patterns:
75
- if re.search(pattern, output_lower, re.IGNORECASE):
76
- return True
77
- return False
78
-
79
- def detect_background_operation(output):
80
- """Detect if output suggests a background operation."""
81
- bg_patterns = [
82
- r"started",
83
- r"running",
84
- r"background",
85
- r"async",
86
- r"task_id",
87
- r"spawned",
88
- ]
89
-
90
- output_lower = output.lower()
91
- for pattern in bg_patterns:
92
- if re.search(pattern, output_lower, re.IGNORECASE):
93
- return True
94
- return False
95
-
96
- def detect_write_failure(output):
97
- """Detect failures in Write/Edit operations."""
98
- error_patterns = [
99
- r"error",
100
- r"failed",
101
- r"permission denied",
102
- r"read-only",
103
- r"not found",
104
- ]
105
-
106
- output_lower = output.lower()
107
- for pattern in error_patterns:
108
- if re.search(pattern, output_lower, re.IGNORECASE):
109
- return True
110
- return False
111
-
112
- def generate_message(tool_name, tool_output, session_id, tool_count):
113
- """Generate contextual message based on tool usage."""
114
- message = ""
115
-
116
- if tool_name == "Bash":
117
- if detect_bash_failure(tool_output):
118
- message = "Command failed. Please investigate the error and fix before continuing."
119
- elif detect_background_operation(tool_output):
120
- message = "Background operation detected. Remember to verify results before proceeding."
121
-
122
- elif tool_name == "Task":
123
- if detect_write_failure(tool_output):
124
- message = "Task delegation failed. Verify agent name and parameters."
125
- elif detect_background_operation(tool_output):
126
- message = "Background task launched. Use TaskOutput to check results when needed."
127
- elif tool_count > 5:
128
- message = f"Multiple tasks delegated ({tool_count} total). Track their completion status."
129
-
130
- elif tool_name == "Edit":
131
- if detect_write_failure(tool_output):
132
- message = "Edit operation failed. Verify file exists and content matches exactly."
133
- else:
134
- message = "Code modified. Verify changes work as expected before marking complete."
135
-
136
- elif tool_name == "Write":
137
- if detect_write_failure(tool_output):
138
- message = "Write operation failed. Check file permissions and directory existence."
139
- else:
140
- message = "File written. Test the changes to ensure they work correctly."
141
-
142
- elif tool_name == "TodoWrite":
143
- output_lower = tool_output.lower()
144
- if re.search(r"created|added", output_lower):
145
- message = "Todo list updated. Proceed with next task on the list."
146
- elif re.search(r"completed|done", output_lower):
147
- message = "Task marked complete. Continue with remaining todos."
148
- elif re.search(r"in_progress", output_lower):
149
- message = "Task marked in progress. Focus on completing this task."
150
-
151
- elif tool_name == "Read":
152
- if tool_count > 10:
153
- message = f"Extensive reading ({tool_count} files). Consider using Grep for pattern searches."
154
-
155
- elif tool_name == "Grep":
156
- if re.search(r"^0$|no matches", tool_output):
157
- message = "No matches found. Verify pattern syntax or try broader search."
158
-
159
- elif tool_name == "Glob":
160
- if not tool_output.strip() or re.search(r"no files", tool_output.lower()):
161
- message = "No files matched pattern. Verify glob syntax and directory."
162
-
163
- return message
164
-
165
- def main():
166
- """Main hook execution."""
167
- try:
168
- # Read JSON input from stdin
169
- input_data = json.load(sys.stdin)
170
-
171
- tool_name = input_data.get("toolName", "")
172
- tool_output = input_data.get("toolOutput", "")
173
- session_id = input_data.get("sessionId", "unknown")
174
- directory = input_data.get("directory", "")
175
-
176
- # Update session statistics
177
- tool_count = update_stats(tool_name, session_id)
178
-
179
- # Generate contextual message
180
- message = generate_message(tool_name, tool_output, session_id, tool_count)
181
-
182
- # Build response JSON (always continue for post-tool hooks)
183
- response = {"continue": True}
184
- if message:
185
- response["message"] = message
186
-
187
- # Output response
188
- print(json.dumps(response, indent=2))
189
-
190
- except Exception as e:
191
- # On error, always continue with no message
192
- print(json.dumps({"continue": True}))
193
- sys.exit(0)
194
-
195
- if __name__ == "__main__":
196
- main()
@@ -1,76 +0,0 @@
1
- #!/bin/bash
2
-
3
- # PreToolUse Hook: Sisyphus Reminder Enforcer
4
- # Injects contextual reminders before every tool execution
5
-
6
- set -euo pipefail
7
-
8
- # Read JSON input from stdin
9
- input=$(cat)
10
-
11
- # Simple JSON extraction using grep/sed (avoids jq dependency)
12
- extract_json_field() {
13
- local field=$1
14
- local default=${2:-""}
15
- echo "$input" | grep -o "\"$field\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | sed 's/.*"\([^"]*\)".*/\1/' || echo "$default"
16
- }
17
-
18
- toolName=$(extract_json_field "toolName" "unknown")
19
- directory=$(extract_json_field "directory" "")
20
-
21
- # Try to get todo count from todo list file (if exists)
22
- todo_file="${directory}/.omc/todos.json"
23
- todo_status=""
24
- if [[ -f "$todo_file" ]] && command -v jq &> /dev/null; then
25
- pending=$(jq -r '[.todos[] | select(.status == "pending")] | length' "$todo_file" 2>/dev/null || echo "0")
26
- in_progress=$(jq -r '[.todos[] | select(.status == "in_progress")] | length' "$todo_file" 2>/dev/null || echo "0")
27
- if [[ $((pending + in_progress)) -gt 0 ]]; then
28
- todo_status="[${in_progress} active, ${pending} pending] "
29
- fi
30
- fi
31
-
32
- # Generate contextual reminder based on tool type
33
- message=""
34
-
35
- case "$toolName" in
36
- TodoWrite)
37
- message="${todo_status}Mark todos in_progress BEFORE starting, completed IMMEDIATELY after finishing."
38
- ;;
39
-
40
- Bash)
41
- message="${todo_status}Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
42
- ;;
43
-
44
- Task)
45
- message="${todo_status}Launch multiple agents in parallel when tasks are independent. Use run_in_background for long operations."
46
- ;;
47
-
48
- Edit|Write)
49
- message="${todo_status}Verify changes work after editing. Test functionality before marking complete."
50
- ;;
51
-
52
- Read)
53
- message="${todo_status}Read multiple files in parallel when possible for faster analysis."
54
- ;;
55
-
56
- Grep|Glob)
57
- message="${todo_status}Combine searches in parallel when investigating multiple patterns."
58
- ;;
59
-
60
- *)
61
- message="${todo_status}The boulder never stops. Continue until all tasks complete."
62
- ;;
63
- esac
64
-
65
- # Return JSON response (always continue, just remind)
66
- # Escape message for JSON (replace " with \", newlines with \n)
67
- escaped_message=$(echo "$message" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | tr '\n' ' ')
68
-
69
- cat <<EOF
70
- {
71
- "continue": true,
72
- "message": "$escaped_message"
73
- }
74
- EOF
75
-
76
- exit 0
@@ -1,18 +0,0 @@
1
- # Sisyphus Mode Aliases for Claude CLI
2
- # Add these to your ~/.bashrc or ~/.zshrc
3
-
4
- # Primary Sisyphus alias - enforces task completion discipline
5
- alias claude-s='/home/bellman/.claude/claude-sisyphus.sh'
6
-
7
- # Work mode alias - shorter alternative
8
- alias claudew='/home/bellman/.claude/claude-sisyphus.sh'
9
-
10
- # Usage examples:
11
- # claude-s "Refactor the API layer"
12
- # claudew "Fix all failing tests"
13
- # claude-s --model opus "Debug this complex issue"
14
-
15
- # Installation:
16
- # 1. Add the aliases above to your shell config (~/.bashrc or ~/.zshrc)
17
- # 2. Reload: source ~/.bashrc (or source ~/.zshrc)
18
- # 3. Use: claude-s "your task here"