@kood/claude-code 0.7.10 → 0.7.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.
@@ -0,0 +1,124 @@
1
+ #!/bin/bash
2
+
3
+ # Ralph Loop Stop Hook
4
+ # Prevents session exit when a ralph-loop is active
5
+ # Feeds Claude's output back as input to continue the loop
6
+
7
+ set -euo pipefail
8
+
9
+ # Read hook input from stdin (advanced stop hook API)
10
+ HOOK_INPUT=$(cat)
11
+
12
+ # Check if ralph-loop is active
13
+ RALPH_STATE_FILE=".claude/ralph-loop.local.md"
14
+
15
+ if [[ ! -f "$RALPH_STATE_FILE" ]]; then
16
+ # No active loop - allow exit
17
+ exit 0
18
+ fi
19
+
20
+ # Parse markdown frontmatter (YAML between ---) and extract values
21
+ FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$RALPH_STATE_FILE")
22
+ ITERATION=$(echo "$FRONTMATTER" | grep '^iteration:' | sed 's/iteration: *//')
23
+ MAX_ITERATIONS=$(echo "$FRONTMATTER" | grep '^max_iterations:' | sed 's/max_iterations: *//')
24
+ # Extract completion_promise and strip surrounding quotes if present
25
+ COMPLETION_PROMISE=$(echo "$FRONTMATTER" | grep '^completion_promise:' | sed 's/completion_promise: *//' | sed 's/^"\(.*\)"$/\1/')
26
+
27
+ # Validate numeric fields before arithmetic operations
28
+ if [[ ! "$ITERATION" =~ ^[0-9]+$ ]]; then
29
+ echo "Warning: Ralph loop state file corrupted (iteration: '$ITERATION')" >&2
30
+ rm "$RALPH_STATE_FILE"
31
+ exit 0
32
+ fi
33
+
34
+ if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
35
+ echo "Warning: Ralph loop state file corrupted (max_iterations: '$MAX_ITERATIONS')" >&2
36
+ rm "$RALPH_STATE_FILE"
37
+ exit 0
38
+ fi
39
+
40
+ # Check if max iterations reached
41
+ if [[ $MAX_ITERATIONS -gt 0 ]] && [[ $ITERATION -ge $MAX_ITERATIONS ]]; then
42
+ echo "Ralph loop: Max iterations ($MAX_ITERATIONS) reached."
43
+ rm "$RALPH_STATE_FILE"
44
+ exit 0
45
+ fi
46
+
47
+ # Get transcript path from hook input
48
+ TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path')
49
+
50
+ if [[ ! -f "$TRANSCRIPT_PATH" ]]; then
51
+ echo "Warning: Ralph loop transcript not found" >&2
52
+ rm "$RALPH_STATE_FILE"
53
+ exit 0
54
+ fi
55
+
56
+ # Read last assistant message from transcript (JSONL format)
57
+ if ! grep -q '"role":"assistant"' "$TRANSCRIPT_PATH"; then
58
+ echo "Warning: No assistant messages in transcript" >&2
59
+ rm "$RALPH_STATE_FILE"
60
+ exit 0
61
+ fi
62
+
63
+ LAST_LINE=$(grep '"role":"assistant"' "$TRANSCRIPT_PATH" | tail -1)
64
+ if [[ -z "$LAST_LINE" ]]; then
65
+ rm "$RALPH_STATE_FILE"
66
+ exit 0
67
+ fi
68
+
69
+ LAST_OUTPUT=$(echo "$LAST_LINE" | jq -r '
70
+ .message.content |
71
+ map(select(.type == "text")) |
72
+ map(.text) |
73
+ join("\n")
74
+ ' 2>&1)
75
+
76
+ if [[ $? -ne 0 ]] || [[ -z "$LAST_OUTPUT" ]]; then
77
+ rm "$RALPH_STATE_FILE"
78
+ exit 0
79
+ fi
80
+
81
+ # Check for completion promise (only if set)
82
+ if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
83
+ PROMISE_TEXT=$(echo "$LAST_OUTPUT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")
84
+
85
+ if [[ -n "$PROMISE_TEXT" ]] && [[ "$PROMISE_TEXT" = "$COMPLETION_PROMISE" ]]; then
86
+ echo "Ralph loop: Detected <promise>$COMPLETION_PROMISE</promise>"
87
+ rm "$RALPH_STATE_FILE"
88
+ exit 0
89
+ fi
90
+ fi
91
+
92
+ # Not complete - continue loop with SAME PROMPT
93
+ NEXT_ITERATION=$((ITERATION + 1))
94
+
95
+ PROMPT_TEXT=$(awk '/^---$/{i++; next} i>=2' "$RALPH_STATE_FILE")
96
+
97
+ if [[ -z "$PROMPT_TEXT" ]]; then
98
+ echo "Warning: Ralph loop state file has no prompt" >&2
99
+ rm "$RALPH_STATE_FILE"
100
+ exit 0
101
+ fi
102
+
103
+ # Update iteration (atomic write)
104
+ TEMP_FILE="${RALPH_STATE_FILE}.tmp.$$"
105
+ sed "s/^iteration: .*/iteration: $NEXT_ITERATION/" "$RALPH_STATE_FILE" > "$TEMP_FILE"
106
+ mv "$TEMP_FILE" "$RALPH_STATE_FILE"
107
+
108
+ # Build system message
109
+ if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
110
+ SYSTEM_MSG="Ralph iteration $NEXT_ITERATION | To stop: output <promise>$COMPLETION_PROMISE</promise> (ONLY when TRUE)"
111
+ else
112
+ SYSTEM_MSG="Ralph iteration $NEXT_ITERATION | No completion promise - loop runs until max iterations"
113
+ fi
114
+
115
+ jq -n \
116
+ --arg prompt "$PROMPT_TEXT" \
117
+ --arg msg "$SYSTEM_MSG" \
118
+ '{
119
+ "decision": "block",
120
+ "reason": $prompt,
121
+ "systemMessage": $msg
122
+ }'
123
+
124
+ exit 0
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ # Session Environment Setup Hook
4
+ # Sets CLAUDE_SCRIPTS_ROOT based on where the command/skill is located
5
+ # - User scope (~/.claude/): CLAUDE_SCRIPTS_ROOT=~/.claude/scripts
6
+ # - Project scope (.claude/): CLAUDE_SCRIPTS_ROOT=.claude/scripts
7
+
8
+ set -euo pipefail
9
+
10
+ # Only run for SessionStart events
11
+ # The hook receives JSON input via stdin, but for SessionStart we just need to set env vars
12
+
13
+ # Determine the scripts root based on installation scope
14
+ # Check if user-level .claude exists and has scripts
15
+ USER_SCRIPTS_DIR="$HOME/.claude/scripts"
16
+ PROJECT_SCRIPTS_DIR=".claude/scripts"
17
+
18
+ # Priority: Project scope first (if exists), then User scope
19
+ if [[ -d "$PROJECT_SCRIPTS_DIR" ]]; then
20
+ SCRIPTS_ROOT="$PROJECT_SCRIPTS_DIR"
21
+ elif [[ -d "$USER_SCRIPTS_DIR" ]]; then
22
+ SCRIPTS_ROOT="$USER_SCRIPTS_DIR"
23
+ else
24
+ # Fallback to project scope (default)
25
+ SCRIPTS_ROOT="$PROJECT_SCRIPTS_DIR"
26
+ fi
27
+
28
+ # Write to CLAUDE_ENV_FILE (session-wide environment)
29
+ if [[ -n "${CLAUDE_ENV_FILE:-}" ]]; then
30
+ echo "CLAUDE_SCRIPTS_ROOT=$SCRIPTS_ROOT" >> "$CLAUDE_ENV_FILE"
31
+ fi
32
+
33
+ exit 0
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # Agent Teams 사용 가능 여부 확인
3
- # Usage: .claude/scripts/agent-teams/check-availability.sh
3
+ # Usage: ${CLAUDE_SCRIPTS_ROOT}/agent-teams/check-availability.sh
4
4
 
5
5
  set -e
6
6
 
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # Agent Teams용 tmux 환경 세팅
3
- # Usage: .claude/scripts/agent-teams/setup-tmux.sh
3
+ # Usage: ${CLAUDE_SCRIPTS_ROOT}/agent-teams/setup-tmux.sh
4
4
 
5
5
  set -e
6
6
 
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # git-merge.sh - 타겟 브랜치에 소스 브랜치를 merge 후 push
3
+ # Usage: ./git-merge.sh <target-branch> <source-branch>
4
+ # Example: ./git-merge.sh deploy/prod dev
5
+
6
+ set -euo pipefail
7
+
8
+ # Git 저장소 확인
9
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
10
+ echo "Error: Not a git repository"
11
+ exit 1
12
+ fi
13
+
14
+ if [ $# -lt 2 ]; then
15
+ echo "Usage: $0 <target-branch> <source-branch>"
16
+ echo "Example: $0 deploy/prod dev"
17
+ exit 1
18
+ fi
19
+
20
+ TARGET="$1"
21
+ SOURCE="$2"
22
+ ORIGINAL_BRANCH=$(git branch --show-current)
23
+
24
+ # Working directory clean 확인
25
+ if [ -n "$(git status --porcelain)" ]; then
26
+ echo "Error: Working directory is not clean. Commit or stash changes first."
27
+ exit 1
28
+ fi
29
+
30
+ # 소스 브랜치 존재 확인
31
+ if ! git rev-parse --verify "$SOURCE" >/dev/null 2>&1; then
32
+ echo "Error: Source branch '$SOURCE' does not exist"
33
+ exit 1
34
+ fi
35
+
36
+ # 타겟 브랜치 존재 확인
37
+ if ! git rev-parse --verify "$TARGET" >/dev/null 2>&1; then
38
+ echo "Error: Target branch '$TARGET' does not exist"
39
+ exit 1
40
+ fi
41
+
42
+ echo "=== Merging '$SOURCE' into '$TARGET' ==="
43
+
44
+ # remote 최신화
45
+ echo "--- Fetching origin ---"
46
+ git fetch origin
47
+
48
+ # 타겟 브랜치로 전환
49
+ echo "--- Checkout '$TARGET' ---"
50
+ git checkout "$TARGET"
51
+
52
+ # 타겟 브랜치 최신화
53
+ echo "--- Pulling latest '$TARGET' ---"
54
+ git pull origin "$TARGET" --ff-only || git pull origin "$TARGET"
55
+
56
+ # 머지 실행
57
+ echo "--- Merging '$SOURCE' into '$TARGET' ---"
58
+ if ! git merge "$SOURCE" --no-edit; then
59
+ echo "Error: Merge conflict detected. Resolve manually."
60
+ echo "You are now on '$TARGET' branch."
61
+ exit 1
62
+ fi
63
+
64
+ # 푸시
65
+ echo "--- Pushing '$TARGET' ---"
66
+ git push origin "$TARGET"
67
+
68
+ # 원래 브랜치로 복귀
69
+ echo "--- Returning to '$ORIGINAL_BRANCH' ---"
70
+ git checkout "$ORIGINAL_BRANCH"
71
+
72
+ echo ""
73
+ echo "Done: Merged '$SOURCE' into '$TARGET' and pushed."
@@ -0,0 +1,161 @@
1
+ #!/bin/bash
2
+
3
+ # Ralph Loop Setup Script
4
+ # Creates state file + ensures Stop hook is registered in User settings
5
+
6
+ set -euo pipefail
7
+
8
+ # --- Hook auto-registration (User settings only, never Project) ---
9
+ ensure_stop_hook() {
10
+ local USER_SETTINGS="$HOME/.claude/settings.json"
11
+ local HOOK_CMD=".claude/hooks/ralph-stop-hook.sh"
12
+
13
+ # Create ~/.claude/ if needed
14
+ mkdir -p "$HOME/.claude"
15
+
16
+ # If no settings file, create with hook
17
+ if [[ ! -f "$USER_SETTINGS" ]]; then
18
+ cat > "$USER_SETTINGS" <<'HOOKEOF'
19
+ {
20
+ "hooks": {
21
+ "Stop": [
22
+ {
23
+ "hooks": [
24
+ {
25
+ "type": "command",
26
+ "command": ".claude/hooks/ralph-stop-hook.sh"
27
+ }
28
+ ]
29
+ }
30
+ ]
31
+ }
32
+ }
33
+ HOOKEOF
34
+ echo "Created $USER_SETTINGS with Ralph stop hook"
35
+ return
36
+ fi
37
+
38
+ # Check if ralph hook already registered (any path containing 'ralph')
39
+ if jq -e '.hooks.Stop // [] | .. | .command? // empty | test("ralph")' "$USER_SETTINGS" >/dev/null 2>&1; then
40
+ return # Already registered
41
+ fi
42
+
43
+ # Add hook to existing settings (preserve all existing values)
44
+ local TEMP_FILE="${USER_SETTINGS}.tmp.$$"
45
+
46
+ # If Stop array exists, append to it; otherwise create it
47
+ if jq -e '.hooks.Stop' "$USER_SETTINGS" >/dev/null 2>&1; then
48
+ jq --arg cmd "$HOOK_CMD" '.hooks.Stop += [{"hooks": [{"type": "command", "command": $cmd}]}]' "$USER_SETTINGS" > "$TEMP_FILE"
49
+ elif jq -e '.hooks' "$USER_SETTINGS" >/dev/null 2>&1; then
50
+ jq --arg cmd "$HOOK_CMD" '.hooks.Stop = [{"hooks": [{"type": "command", "command": $cmd}]}]' "$USER_SETTINGS" > "$TEMP_FILE"
51
+ else
52
+ jq --arg cmd "$HOOK_CMD" '.hooks = {"Stop": [{"hooks": [{"type": "command", "command": $cmd}]}]}' "$USER_SETTINGS" > "$TEMP_FILE"
53
+ fi
54
+
55
+ mv "$TEMP_FILE" "$USER_SETTINGS"
56
+ echo "Registered Ralph stop hook in $USER_SETTINGS"
57
+ }
58
+
59
+ ensure_stop_hook
60
+
61
+ # --- Argument parsing ---
62
+ PROMPT_PARTS=()
63
+ MAX_ITERATIONS=0
64
+ COMPLETION_PROMISE="null"
65
+
66
+ while [[ $# -gt 0 ]]; do
67
+ case $1 in
68
+ -h|--help)
69
+ cat << 'HELP_EOF'
70
+ Ralph Loop - Interactive self-referential development loop
71
+
72
+ USAGE:
73
+ /ralph-loop [PROMPT...] [OPTIONS]
74
+
75
+ OPTIONS:
76
+ --max-iterations <n> Maximum iterations (default: unlimited)
77
+ --completion-promise '<text>' Promise phrase (USE QUOTES for multi-word)
78
+ -h, --help Show this help
79
+
80
+ EXAMPLES:
81
+ /ralph-loop Build a todo API --completion-promise 'DONE' --max-iterations 20
82
+ /ralph-loop --max-iterations 10 Fix the auth bug
83
+ /ralph-loop Refactor cache layer (runs forever)
84
+
85
+ STOPPING:
86
+ Only by reaching --max-iterations or detecting --completion-promise
87
+
88
+ MONITORING:
89
+ grep '^iteration:' .claude/ralph-loop.local.md
90
+ HELP_EOF
91
+ exit 0
92
+ ;;
93
+ --max-iterations)
94
+ if [[ -z "${2:-}" ]] || ! [[ "$2" =~ ^[0-9]+$ ]]; then
95
+ echo "Error: --max-iterations requires a positive integer" >&2
96
+ exit 1
97
+ fi
98
+ MAX_ITERATIONS="$2"
99
+ shift 2
100
+ ;;
101
+ --completion-promise)
102
+ if [[ -z "${2:-}" ]]; then
103
+ echo "Error: --completion-promise requires a text argument" >&2
104
+ exit 1
105
+ fi
106
+ COMPLETION_PROMISE="$2"
107
+ shift 2
108
+ ;;
109
+ *)
110
+ PROMPT_PARTS+=("$1")
111
+ shift
112
+ ;;
113
+ esac
114
+ done
115
+
116
+ PROMPT="${PROMPT_PARTS[*]}"
117
+
118
+ if [[ -z "$PROMPT" ]]; then
119
+ echo "Error: No prompt provided" >&2
120
+ echo "Usage: /ralph-loop <PROMPT> [--max-iterations N] [--completion-promise TEXT]" >&2
121
+ exit 1
122
+ fi
123
+
124
+ # --- Create state file ---
125
+ mkdir -p .claude
126
+
127
+ if [[ -n "$COMPLETION_PROMISE" ]] && [[ "$COMPLETION_PROMISE" != "null" ]]; then
128
+ COMPLETION_PROMISE_YAML="\"$COMPLETION_PROMISE\""
129
+ else
130
+ COMPLETION_PROMISE_YAML="null"
131
+ fi
132
+
133
+ cat > .claude/ralph-loop.local.md <<EOF
134
+ ---
135
+ active: true
136
+ iteration: 1
137
+ max_iterations: $MAX_ITERATIONS
138
+ completion_promise: $COMPLETION_PROMISE_YAML
139
+ started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
140
+ ---
141
+
142
+ $PROMPT
143
+ EOF
144
+
145
+ cat <<EOF
146
+ Ralph loop activated!
147
+
148
+ Iteration: 1
149
+ Max iterations: $(if [[ $MAX_ITERATIONS -gt 0 ]]; then echo $MAX_ITERATIONS; else echo "unlimited"; fi)
150
+ Completion promise: $(if [[ "$COMPLETION_PROMISE" != "null" ]]; then echo "$COMPLETION_PROMISE"; else echo "none (runs forever)"; fi)
151
+
152
+ The stop hook blocks exit and re-feeds the same prompt each iteration.
153
+
154
+ EOF
155
+
156
+ echo "$PROMPT"
157
+
158
+ if [[ "$COMPLETION_PROMISE" != "null" ]]; then
159
+ echo ""
160
+ echo "To complete: output <promise>$COMPLETION_PROMISE</promise> (ONLY when TRUE)"
161
+ fi