Ver código fonte

Add caffeinate plugin to prevent blocking sleep commands

This plugin intercepts sleep commands in Bash and prompts Claude to use
background execution (run_in_background: true) instead. This keeps the
session responsive during long-running operations.

Features:
- Blocks sleep commands with helpful retry message
- Allows sleep in quoted strings (false positive prevention)
- Catches sleep in compound commands (&&, ||, ;) and loops
- Allows background commands through (run_in_background: true)

:house: Remote-Dev: homespace

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 6
Claude-Permission-Prompts: 0
Claude-Escapes: 0
Daisy Hollman 8 meses atrás
pai
commit
95380b3cd5

+ 11 - 0
.claude-plugin/marketplace.json

@@ -328,6 +328,17 @@
       "category": "productivity",
       "homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/code-simplifier"
     },
+    {
+      "name": "caffeinate",
+      "description": "Prevents blocking sleep commands by intercepting them and prompting Claude to use background execution instead. Keeps your session responsive during long-running operations.",
+      "author": {
+        "name": "Anthropic",
+        "email": "support@anthropic.com"
+      },
+      "source": "./plugins/caffeinate",
+      "category": "productivity",
+      "homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/caffeinate"
+    },
     {
       "name": "explanatory-output-style",
       "description": "Adds educational insights about implementation choices and codebase patterns (mimics the deprecated Explanatory output style)",

+ 10 - 0
plugins/caffeinate/.claude-plugin/plugin.json

@@ -0,0 +1,10 @@
+{
+  "name": "caffeinate",
+  "version": "0.1.0",
+  "description": "Blocks sleep commands and reminds Claude to use background tasks instead",
+  "author": {
+    "name": "Anthropic",
+    "email": "support@anthropic.com"
+  },
+  "keywords": ["productivity", "hooks", "bash", "background-tasks"]
+}

+ 58 - 0
plugins/caffeinate/README.md

@@ -0,0 +1,58 @@
+# Caffeinate
+
+A Claude Code plugin that blocks `sleep` commands and reminds Claude to use background tasks instead.
+
+## Purpose
+
+When Claude uses `sleep` commands in Bash, it blocks the session unnecessarily. This plugin intercepts these commands and suggests using proper async patterns like:
+
+- `run_in_background: true` parameter for long-running commands
+- Polling for conditions instead of sleeping
+- Proper async/background task patterns
+
+## Installation
+
+```bash
+# From the plugin directory
+claude --plugin-dir /path/to/caffeinate
+```
+
+Or copy to your project's `.claude-plugin/` directory.
+
+## What Gets Blocked
+
+| Command | Blocked? | Reason |
+|---------|----------|--------|
+| `sleep 5` | Yes | Direct sleep command |
+| `sleep $TIMEOUT` | Yes | Sleep with variable |
+| `echo "test" && sleep 5` | Yes | Sleep after separator, outside quotes |
+| `cmd; sleep 10` | Yes | Sleep after semicolon |
+| `echo "sleep 8 hours"` | No | Sleep is inside quotes (not a command) |
+| `echo "foo && sleep 5"` | No | Entire sleep pattern is in a string |
+
+## How It Works
+
+The plugin uses a `PreToolUse` hook on the `Bash` tool to:
+
+1. Check if commands start with `sleep`
+2. Detect `sleep` after command separators (`&&`, `||`, `;`, `|`)
+3. Use quote-counting to avoid false positives when `sleep` appears inside strings
+
+## Alternatives to Sleep
+
+Instead of:
+```bash
+sleep 5 && check_status
+```
+
+Use background execution:
+```bash
+# Run in background with run_in_background: true
+long_running_command
+```
+
+Or poll for conditions:
+```bash
+# Poll for a file to exist
+while [ ! -f /tmp/ready ]; do :; done
+```

+ 17 - 0
plugins/caffeinate/hooks/hooks.json

@@ -0,0 +1,17 @@
+{
+  "description": "Blocks sleep commands and reminds Claude to use background tasks",
+  "hooks": {
+    "PreToolUse": [
+      {
+        "matcher": "Bash",
+        "hooks": [
+          {
+            "type": "command",
+            "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-sleep.sh",
+            "timeout": 5
+          }
+        ]
+      }
+    ]
+  }
+}

+ 61 - 0
plugins/caffeinate/hooks/scripts/check-sleep.sh

@@ -0,0 +1,61 @@
+#!/bin/bash
+# Caffeinate hook: Blocks sleep commands and suggests background tasks
+set -euo pipefail
+
+input=$(cat)
+command=$(echo "$input" | jq -r '.tool_input.command // empty')
+
+if [[ -z "$command" ]]; then
+  exit 0
+fi
+
+# Allow sleep if run_in_background is true - that's the whole point!
+run_in_bg=$(echo "$input" | jq -r '.tool_input.run_in_background // false')
+if [[ "$run_in_bg" == "true" ]]; then
+  exit 0
+fi
+
+block_message='ACTION REQUIRED: Your sleep command was blocked. You MUST now call Bash again with the SAME command but add the parameter run_in_background: true. Do this immediately in your next tool call. Do not explain or apologize - just retry with run_in_background: true.'
+
+output_block() {
+  # Output JSON to stdout for blocking decision
+  # Output message to stderr to feed back to Claude
+  cat << EOF
+{
+  "hookSpecificOutput": {
+    "hookEventName": "PreToolUse",
+    "permissionDecision": "deny",
+    "permissionDecisionReason": "$block_message"
+  }
+}
+EOF
+  exit 0
+}
+
+# Remove all quoted strings to avoid false positives
+# Replace single and double quoted strings with placeholder
+cmd_no_quotes=$(echo "$command" | sed -E "s/\"[^\"]*\"//g; s/'[^']*'//g")
+
+# Check for sleep command patterns in the de-quoted command
+# Pattern 1: Command starts with sleep
+if [[ "$cmd_no_quotes" =~ (^|[[:space:]])sleep[[:space:]]+[0-9] ]]; then
+  output_block
+fi
+
+# Pattern 2: sleep after any common separator (&&, ||, ;, |, do, then)
+if [[ "$cmd_no_quotes" =~ (\&\&|;\||[[:space:]]do[[:space:]]|[[:space:]]then[[:space:]])[[:space:]]*sleep[[:space:]] ]]; then
+  output_block
+fi
+
+# Pattern 3: Simple contains check - if "sleep " followed by number appears anywhere
+if [[ "$cmd_no_quotes" =~ sleep[[:space:]]+[0-9] ]]; then
+  output_block
+fi
+
+# Pattern 4: sleep with variable like $TIMEOUT or ${DELAY}
+if [[ "$cmd_no_quotes" =~ sleep[[:space:]]+\$ ]]; then
+  output_block
+fi
+
+# No sleep command detected - allow
+exit 0