@atlashub/smartstack-cli 1.5.0 → 1.5.2
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/.documentation/agents.html +920 -916
- package/.documentation/apex.html +1022 -1018
- package/.documentation/business-analyse.html +1505 -1501
- package/.documentation/commands.html +684 -680
- package/.documentation/css/styles.css +2168 -2168
- package/.documentation/efcore.html +2509 -2505
- package/.documentation/gitflow.html +2622 -2618
- package/.documentation/hooks.html +417 -413
- package/.documentation/index.html +327 -323
- package/.documentation/init.html +565 -0
- package/.documentation/installation.html +548 -462
- package/.documentation/js/app.js +794 -794
- package/.documentation/ralph-loop.html +534 -530
- package/.documentation/test-web.html +517 -513
- package/config/default-config.json +86 -86
- package/config/settings.json +53 -53
- package/config/settings.local.example.json +16 -16
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/package.json +88 -88
- package/templates/agents/action.md +36 -36
- package/templates/agents/efcore/conflicts.md +84 -84
- package/templates/agents/efcore/db-deploy.md +51 -51
- package/templates/agents/efcore/db-reset.md +59 -59
- package/templates/agents/efcore/db-seed.md +56 -56
- package/templates/agents/efcore/db-status.md +64 -64
- package/templates/agents/efcore/migration.md +85 -85
- package/templates/agents/efcore/rebase-snapshot.md +62 -62
- package/templates/agents/efcore/scan.md +90 -90
- package/templates/agents/efcore/squash.md +67 -67
- package/templates/agents/explore-codebase.md +65 -65
- package/templates/agents/explore-docs.md +97 -97
- package/templates/agents/fix-grammar.md +49 -49
- package/templates/agents/gitflow/abort.md +45 -45
- package/templates/agents/gitflow/cleanup.md +85 -85
- package/templates/agents/gitflow/commit.md +40 -40
- package/templates/agents/gitflow/exec.md +48 -48
- package/templates/agents/gitflow/finish.md +92 -92
- package/templates/agents/gitflow/init.md +139 -139
- package/templates/agents/gitflow/merge.md +62 -62
- package/templates/agents/gitflow/plan.md +42 -42
- package/templates/agents/gitflow/pr.md +78 -78
- package/templates/agents/gitflow/review.md +49 -49
- package/templates/agents/gitflow/start.md +61 -61
- package/templates/agents/gitflow/status.md +32 -32
- package/templates/agents/snipper.md +36 -36
- package/templates/agents/websearch.md +46 -46
- package/templates/commands/_resources/formatting-guide.md +124 -124
- package/templates/commands/ai-prompt.md +315 -315
- package/templates/commands/apex/1-analyze.md +100 -100
- package/templates/commands/apex/2-plan.md +145 -145
- package/templates/commands/apex/3-execute.md +171 -171
- package/templates/commands/apex/4-examine.md +116 -116
- package/templates/commands/apex/5-tasks.md +209 -209
- package/templates/commands/apex.md +76 -76
- package/templates/commands/application/create.md +362 -362
- package/templates/commands/application/templates-backend.md +463 -463
- package/templates/commands/application/templates-frontend.md +517 -517
- package/templates/commands/application/templates-i18n.md +478 -478
- package/templates/commands/application/templates-seed.md +362 -362
- package/templates/commands/application.md +303 -303
- package/templates/commands/business-analyse/0-orchestrate.md +640 -640
- package/templates/commands/business-analyse/1-init.md +269 -269
- package/templates/commands/business-analyse/2-discover.md +520 -520
- package/templates/commands/business-analyse/3-analyse.md +408 -408
- package/templates/commands/business-analyse/4-specify.md +598 -598
- package/templates/commands/business-analyse/5-validate.md +326 -326
- package/templates/commands/business-analyse/6-handoff.md +746 -746
- package/templates/commands/business-analyse/7-doc-html.md +602 -602
- package/templates/commands/business-analyse/bug.md +325 -325
- package/templates/commands/business-analyse/change-request.md +368 -368
- package/templates/commands/business-analyse/hotfix.md +200 -200
- package/templates/commands/business-analyse.md +640 -640
- package/templates/commands/controller/create.md +216 -216
- package/templates/commands/controller/postman-templates.md +528 -528
- package/templates/commands/controller/templates.md +600 -600
- package/templates/commands/controller.md +337 -337
- package/templates/commands/create/agent.md +138 -138
- package/templates/commands/create/command.md +166 -166
- package/templates/commands/create/hook.md +234 -234
- package/templates/commands/create/plugin.md +329 -329
- package/templates/commands/create/project.md +507 -507
- package/templates/commands/create/skill.md +199 -199
- package/templates/commands/create.md +220 -220
- package/templates/commands/debug.md +95 -95
- package/templates/commands/documentation/module.md +202 -202
- package/templates/commands/documentation/templates.md +432 -432
- package/templates/commands/documentation.md +190 -190
- package/templates/commands/efcore/_env-check.md +153 -153
- package/templates/commands/efcore/conflicts.md +186 -186
- package/templates/commands/efcore/db-deploy.md +193 -193
- package/templates/commands/efcore/db-reset.md +426 -426
- package/templates/commands/efcore/db-seed.md +326 -326
- package/templates/commands/efcore/db-status.md +226 -226
- package/templates/commands/efcore/migration.md +400 -400
- package/templates/commands/efcore/rebase-snapshot.md +264 -264
- package/templates/commands/efcore/scan.md +198 -198
- package/templates/commands/efcore/squash.md +298 -298
- package/templates/commands/efcore.md +224 -224
- package/templates/commands/epct.md +69 -69
- package/templates/commands/explain.md +186 -186
- package/templates/commands/explore.md +45 -45
- package/templates/commands/feature-full.md +267 -267
- package/templates/commands/gitflow/1-init.md +1038 -1038
- package/templates/commands/gitflow/10-start.md +768 -768
- package/templates/commands/gitflow/11-finish.md +457 -457
- package/templates/commands/gitflow/12-cleanup.md +276 -276
- package/templates/commands/gitflow/13-sync.md +216 -216
- package/templates/commands/gitflow/14-rebase.md +251 -251
- package/templates/commands/gitflow/2-status.md +277 -277
- package/templates/commands/gitflow/3-commit.md +344 -344
- package/templates/commands/gitflow/4-plan.md +145 -145
- package/templates/commands/gitflow/5-exec.md +147 -147
- package/templates/commands/gitflow/6-abort.md +344 -344
- package/templates/commands/gitflow/7-pull-request.md +453 -355
- package/templates/commands/gitflow/8-review.md +240 -176
- package/templates/commands/gitflow/9-merge.md +451 -365
- package/templates/commands/gitflow.md +128 -128
- package/templates/commands/implement.md +663 -663
- package/templates/commands/init.md +567 -562
- package/templates/commands/mcp-integration.md +330 -330
- package/templates/commands/notification.md +129 -129
- package/templates/commands/oneshot.md +57 -57
- package/templates/commands/quick-search.md +72 -72
- package/templates/commands/ralph-loop/cancel-ralph.md +18 -18
- package/templates/commands/ralph-loop/help.md +126 -126
- package/templates/commands/ralph-loop/ralph-loop.md +18 -18
- package/templates/commands/review.md +106 -106
- package/templates/commands/utils/test-web-config.md +160 -160
- package/templates/commands/utils/test-web.md +151 -151
- package/templates/commands/validate.md +233 -233
- package/templates/commands/workflow.md +193 -193
- package/templates/gitflow/config.json +138 -138
- package/templates/hooks/ef-migration-check.md +139 -139
- package/templates/hooks/hooks.json +25 -25
- package/templates/hooks/stop-hook.sh +177 -177
- package/templates/skills/ai-prompt/SKILL.md +778 -778
- package/templates/skills/application/SKILL.md +563 -563
- package/templates/skills/application/templates-backend.md +450 -450
- package/templates/skills/application/templates-frontend.md +531 -531
- package/templates/skills/application/templates-i18n.md +520 -520
- package/templates/skills/application/templates-seed.md +647 -647
- package/templates/skills/business-analyse/SKILL.md +191 -191
- package/templates/skills/business-analyse/questionnaire.md +283 -283
- package/templates/skills/business-analyse/templates-frd.md +477 -477
- package/templates/skills/business-analyse/templates-react.md +580 -580
- package/templates/skills/controller/SKILL.md +240 -240
- package/templates/skills/controller/postman-templates.md +614 -614
- package/templates/skills/controller/templates.md +1468 -1468
- package/templates/skills/documentation/SKILL.md +133 -133
- package/templates/skills/documentation/templates.md +476 -476
- package/templates/skills/feature-full/SKILL.md +838 -838
- package/templates/skills/notification/SKILL.md +555 -555
- package/templates/skills/ui-components/SKILL.md +870 -870
- package/templates/skills/workflow/SKILL.md +582 -582
- package/templates/test-web/api-health.json +38 -38
- package/templates/test-web/minimal.json +19 -19
- package/templates/test-web/npm-package.json +46 -46
- package/templates/test-web/seo-check.json +54 -54
|
@@ -1,177 +1,177 @@
|
|
|
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 "⚠️ Ralph loop: State file corrupted" >&2
|
|
30
|
-
echo " File: $RALPH_STATE_FILE" >&2
|
|
31
|
-
echo " Problem: 'iteration' field is not a valid number (got: '$ITERATION')" >&2
|
|
32
|
-
echo "" >&2
|
|
33
|
-
echo " This usually means the state file was manually edited or corrupted." >&2
|
|
34
|
-
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
35
|
-
rm "$RALPH_STATE_FILE"
|
|
36
|
-
exit 0
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
|
|
40
|
-
echo "⚠️ Ralph loop: State file corrupted" >&2
|
|
41
|
-
echo " File: $RALPH_STATE_FILE" >&2
|
|
42
|
-
echo " Problem: 'max_iterations' field is not a valid number (got: '$MAX_ITERATIONS')" >&2
|
|
43
|
-
echo "" >&2
|
|
44
|
-
echo " This usually means the state file was manually edited or corrupted." >&2
|
|
45
|
-
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
46
|
-
rm "$RALPH_STATE_FILE"
|
|
47
|
-
exit 0
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
# Check if max iterations reached
|
|
51
|
-
if [[ $MAX_ITERATIONS -gt 0 ]] && [[ $ITERATION -ge $MAX_ITERATIONS ]]; then
|
|
52
|
-
echo "🛑 Ralph loop: Max iterations ($MAX_ITERATIONS) reached."
|
|
53
|
-
rm "$RALPH_STATE_FILE"
|
|
54
|
-
exit 0
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
# Get transcript path from hook input
|
|
58
|
-
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path')
|
|
59
|
-
|
|
60
|
-
if [[ ! -f "$TRANSCRIPT_PATH" ]]; then
|
|
61
|
-
echo "⚠️ Ralph loop: Transcript file not found" >&2
|
|
62
|
-
echo " Expected: $TRANSCRIPT_PATH" >&2
|
|
63
|
-
echo " This is unusual and may indicate a Claude Code internal issue." >&2
|
|
64
|
-
echo " Ralph loop is stopping." >&2
|
|
65
|
-
rm "$RALPH_STATE_FILE"
|
|
66
|
-
exit 0
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# Read last assistant message from transcript (JSONL format - one JSON per line)
|
|
70
|
-
# First check if there are any assistant messages
|
|
71
|
-
if ! grep -q '"role":"assistant"' "$TRANSCRIPT_PATH"; then
|
|
72
|
-
echo "⚠️ Ralph loop: No assistant messages found in transcript" >&2
|
|
73
|
-
echo " Transcript: $TRANSCRIPT_PATH" >&2
|
|
74
|
-
echo " This is unusual and may indicate a transcript format issue" >&2
|
|
75
|
-
echo " Ralph loop is stopping." >&2
|
|
76
|
-
rm "$RALPH_STATE_FILE"
|
|
77
|
-
exit 0
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
# Extract last assistant message with explicit error handling
|
|
81
|
-
LAST_LINE=$(grep '"role":"assistant"' "$TRANSCRIPT_PATH" | tail -1)
|
|
82
|
-
if [[ -z "$LAST_LINE" ]]; then
|
|
83
|
-
echo "⚠️ Ralph loop: Failed to extract last assistant message" >&2
|
|
84
|
-
echo " Ralph loop is stopping." >&2
|
|
85
|
-
rm "$RALPH_STATE_FILE"
|
|
86
|
-
exit 0
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
# Parse JSON with error handling
|
|
90
|
-
LAST_OUTPUT=$(echo "$LAST_LINE" | jq -r '
|
|
91
|
-
.message.content |
|
|
92
|
-
map(select(.type == "text")) |
|
|
93
|
-
map(.text) |
|
|
94
|
-
join("\n")
|
|
95
|
-
' 2>&1)
|
|
96
|
-
|
|
97
|
-
# Check if jq succeeded
|
|
98
|
-
if [[ $? -ne 0 ]]; then
|
|
99
|
-
echo "⚠️ Ralph loop: Failed to parse assistant message JSON" >&2
|
|
100
|
-
echo " Error: $LAST_OUTPUT" >&2
|
|
101
|
-
echo " This may indicate a transcript format issue" >&2
|
|
102
|
-
echo " Ralph loop is stopping." >&2
|
|
103
|
-
rm "$RALPH_STATE_FILE"
|
|
104
|
-
exit 0
|
|
105
|
-
fi
|
|
106
|
-
|
|
107
|
-
if [[ -z "$LAST_OUTPUT" ]]; then
|
|
108
|
-
echo "⚠️ Ralph loop: Assistant message contained no text content" >&2
|
|
109
|
-
echo " Ralph loop is stopping." >&2
|
|
110
|
-
rm "$RALPH_STATE_FILE"
|
|
111
|
-
exit 0
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
# Check for completion promise (only if set)
|
|
115
|
-
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
116
|
-
# Extract text from <promise> tags using Perl for multiline support
|
|
117
|
-
# -0777 slurps entire input, s flag makes . match newlines
|
|
118
|
-
# .*? is non-greedy (takes FIRST tag), whitespace normalized
|
|
119
|
-
PROMISE_TEXT=$(echo "$LAST_OUTPUT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")
|
|
120
|
-
|
|
121
|
-
# Use = for literal string comparison (not pattern matching)
|
|
122
|
-
# == in [[ ]] does glob pattern matching which breaks with *, ?, [ characters
|
|
123
|
-
if [[ -n "$PROMISE_TEXT" ]] && [[ "$PROMISE_TEXT" = "$COMPLETION_PROMISE" ]]; then
|
|
124
|
-
echo "✅ Ralph loop: Detected <promise>$COMPLETION_PROMISE</promise>"
|
|
125
|
-
rm "$RALPH_STATE_FILE"
|
|
126
|
-
exit 0
|
|
127
|
-
fi
|
|
128
|
-
fi
|
|
129
|
-
|
|
130
|
-
# Not complete - continue loop with SAME PROMPT
|
|
131
|
-
NEXT_ITERATION=$((ITERATION + 1))
|
|
132
|
-
|
|
133
|
-
# Extract prompt (everything after the closing ---)
|
|
134
|
-
# Skip first --- line, skip until second --- line, then print everything after
|
|
135
|
-
# Use i>=2 instead of i==2 to handle --- in prompt content
|
|
136
|
-
PROMPT_TEXT=$(awk '/^---$/{i++; next} i>=2' "$RALPH_STATE_FILE")
|
|
137
|
-
|
|
138
|
-
if [[ -z "$PROMPT_TEXT" ]]; then
|
|
139
|
-
echo "⚠️ Ralph loop: State file corrupted or incomplete" >&2
|
|
140
|
-
echo " File: $RALPH_STATE_FILE" >&2
|
|
141
|
-
echo " Problem: No prompt text found" >&2
|
|
142
|
-
echo "" >&2
|
|
143
|
-
echo " This usually means:" >&2
|
|
144
|
-
echo " • State file was manually edited" >&2
|
|
145
|
-
echo " • File was corrupted during writing" >&2
|
|
146
|
-
echo "" >&2
|
|
147
|
-
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
148
|
-
rm "$RALPH_STATE_FILE"
|
|
149
|
-
exit 0
|
|
150
|
-
fi
|
|
151
|
-
|
|
152
|
-
# Update iteration in frontmatter (portable across macOS and Linux)
|
|
153
|
-
# Create temp file, then atomically replace
|
|
154
|
-
TEMP_FILE="${RALPH_STATE_FILE}.tmp.$$"
|
|
155
|
-
sed "s/^iteration: .*/iteration: $NEXT_ITERATION/" "$RALPH_STATE_FILE" > "$TEMP_FILE"
|
|
156
|
-
mv "$TEMP_FILE" "$RALPH_STATE_FILE"
|
|
157
|
-
|
|
158
|
-
# Build system message with iteration count and completion promise info
|
|
159
|
-
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
160
|
-
SYSTEM_MSG="🔄 Ralph iteration $NEXT_ITERATION | To stop: output <promise>$COMPLETION_PROMISE</promise> (ONLY when statement is TRUE - do not lie to exit!)"
|
|
161
|
-
else
|
|
162
|
-
SYSTEM_MSG="🔄 Ralph iteration $NEXT_ITERATION | No completion promise set - loop runs infinitely"
|
|
163
|
-
fi
|
|
164
|
-
|
|
165
|
-
# Output JSON to block the stop and feed prompt back
|
|
166
|
-
# The "reason" field contains the prompt that will be sent back to Claude
|
|
167
|
-
jq -n \
|
|
168
|
-
--arg prompt "$PROMPT_TEXT" \
|
|
169
|
-
--arg msg "$SYSTEM_MSG" \
|
|
170
|
-
'{
|
|
171
|
-
"decision": "block",
|
|
172
|
-
"reason": $prompt,
|
|
173
|
-
"systemMessage": $msg
|
|
174
|
-
}'
|
|
175
|
-
|
|
176
|
-
# Exit 0 for successful hook execution
|
|
177
|
-
exit 0
|
|
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 "⚠️ Ralph loop: State file corrupted" >&2
|
|
30
|
+
echo " File: $RALPH_STATE_FILE" >&2
|
|
31
|
+
echo " Problem: 'iteration' field is not a valid number (got: '$ITERATION')" >&2
|
|
32
|
+
echo "" >&2
|
|
33
|
+
echo " This usually means the state file was manually edited or corrupted." >&2
|
|
34
|
+
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
35
|
+
rm "$RALPH_STATE_FILE"
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
|
|
40
|
+
echo "⚠️ Ralph loop: State file corrupted" >&2
|
|
41
|
+
echo " File: $RALPH_STATE_FILE" >&2
|
|
42
|
+
echo " Problem: 'max_iterations' field is not a valid number (got: '$MAX_ITERATIONS')" >&2
|
|
43
|
+
echo "" >&2
|
|
44
|
+
echo " This usually means the state file was manually edited or corrupted." >&2
|
|
45
|
+
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
46
|
+
rm "$RALPH_STATE_FILE"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Check if max iterations reached
|
|
51
|
+
if [[ $MAX_ITERATIONS -gt 0 ]] && [[ $ITERATION -ge $MAX_ITERATIONS ]]; then
|
|
52
|
+
echo "🛑 Ralph loop: Max iterations ($MAX_ITERATIONS) reached."
|
|
53
|
+
rm "$RALPH_STATE_FILE"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Get transcript path from hook input
|
|
58
|
+
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path')
|
|
59
|
+
|
|
60
|
+
if [[ ! -f "$TRANSCRIPT_PATH" ]]; then
|
|
61
|
+
echo "⚠️ Ralph loop: Transcript file not found" >&2
|
|
62
|
+
echo " Expected: $TRANSCRIPT_PATH" >&2
|
|
63
|
+
echo " This is unusual and may indicate a Claude Code internal issue." >&2
|
|
64
|
+
echo " Ralph loop is stopping." >&2
|
|
65
|
+
rm "$RALPH_STATE_FILE"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Read last assistant message from transcript (JSONL format - one JSON per line)
|
|
70
|
+
# First check if there are any assistant messages
|
|
71
|
+
if ! grep -q '"role":"assistant"' "$TRANSCRIPT_PATH"; then
|
|
72
|
+
echo "⚠️ Ralph loop: No assistant messages found in transcript" >&2
|
|
73
|
+
echo " Transcript: $TRANSCRIPT_PATH" >&2
|
|
74
|
+
echo " This is unusual and may indicate a transcript format issue" >&2
|
|
75
|
+
echo " Ralph loop is stopping." >&2
|
|
76
|
+
rm "$RALPH_STATE_FILE"
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Extract last assistant message with explicit error handling
|
|
81
|
+
LAST_LINE=$(grep '"role":"assistant"' "$TRANSCRIPT_PATH" | tail -1)
|
|
82
|
+
if [[ -z "$LAST_LINE" ]]; then
|
|
83
|
+
echo "⚠️ Ralph loop: Failed to extract last assistant message" >&2
|
|
84
|
+
echo " Ralph loop is stopping." >&2
|
|
85
|
+
rm "$RALPH_STATE_FILE"
|
|
86
|
+
exit 0
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Parse JSON with error handling
|
|
90
|
+
LAST_OUTPUT=$(echo "$LAST_LINE" | jq -r '
|
|
91
|
+
.message.content |
|
|
92
|
+
map(select(.type == "text")) |
|
|
93
|
+
map(.text) |
|
|
94
|
+
join("\n")
|
|
95
|
+
' 2>&1)
|
|
96
|
+
|
|
97
|
+
# Check if jq succeeded
|
|
98
|
+
if [[ $? -ne 0 ]]; then
|
|
99
|
+
echo "⚠️ Ralph loop: Failed to parse assistant message JSON" >&2
|
|
100
|
+
echo " Error: $LAST_OUTPUT" >&2
|
|
101
|
+
echo " This may indicate a transcript format issue" >&2
|
|
102
|
+
echo " Ralph loop is stopping." >&2
|
|
103
|
+
rm "$RALPH_STATE_FILE"
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
if [[ -z "$LAST_OUTPUT" ]]; then
|
|
108
|
+
echo "⚠️ Ralph loop: Assistant message contained no text content" >&2
|
|
109
|
+
echo " Ralph loop is stopping." >&2
|
|
110
|
+
rm "$RALPH_STATE_FILE"
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Check for completion promise (only if set)
|
|
115
|
+
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
116
|
+
# Extract text from <promise> tags using Perl for multiline support
|
|
117
|
+
# -0777 slurps entire input, s flag makes . match newlines
|
|
118
|
+
# .*? is non-greedy (takes FIRST tag), whitespace normalized
|
|
119
|
+
PROMISE_TEXT=$(echo "$LAST_OUTPUT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")
|
|
120
|
+
|
|
121
|
+
# Use = for literal string comparison (not pattern matching)
|
|
122
|
+
# == in [[ ]] does glob pattern matching which breaks with *, ?, [ characters
|
|
123
|
+
if [[ -n "$PROMISE_TEXT" ]] && [[ "$PROMISE_TEXT" = "$COMPLETION_PROMISE" ]]; then
|
|
124
|
+
echo "✅ Ralph loop: Detected <promise>$COMPLETION_PROMISE</promise>"
|
|
125
|
+
rm "$RALPH_STATE_FILE"
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Not complete - continue loop with SAME PROMPT
|
|
131
|
+
NEXT_ITERATION=$((ITERATION + 1))
|
|
132
|
+
|
|
133
|
+
# Extract prompt (everything after the closing ---)
|
|
134
|
+
# Skip first --- line, skip until second --- line, then print everything after
|
|
135
|
+
# Use i>=2 instead of i==2 to handle --- in prompt content
|
|
136
|
+
PROMPT_TEXT=$(awk '/^---$/{i++; next} i>=2' "$RALPH_STATE_FILE")
|
|
137
|
+
|
|
138
|
+
if [[ -z "$PROMPT_TEXT" ]]; then
|
|
139
|
+
echo "⚠️ Ralph loop: State file corrupted or incomplete" >&2
|
|
140
|
+
echo " File: $RALPH_STATE_FILE" >&2
|
|
141
|
+
echo " Problem: No prompt text found" >&2
|
|
142
|
+
echo "" >&2
|
|
143
|
+
echo " This usually means:" >&2
|
|
144
|
+
echo " • State file was manually edited" >&2
|
|
145
|
+
echo " • File was corrupted during writing" >&2
|
|
146
|
+
echo "" >&2
|
|
147
|
+
echo " Ralph loop is stopping. Run /ralph-loop again to start fresh." >&2
|
|
148
|
+
rm "$RALPH_STATE_FILE"
|
|
149
|
+
exit 0
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Update iteration in frontmatter (portable across macOS and Linux)
|
|
153
|
+
# Create temp file, then atomically replace
|
|
154
|
+
TEMP_FILE="${RALPH_STATE_FILE}.tmp.$$"
|
|
155
|
+
sed "s/^iteration: .*/iteration: $NEXT_ITERATION/" "$RALPH_STATE_FILE" > "$TEMP_FILE"
|
|
156
|
+
mv "$TEMP_FILE" "$RALPH_STATE_FILE"
|
|
157
|
+
|
|
158
|
+
# Build system message with iteration count and completion promise info
|
|
159
|
+
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
160
|
+
SYSTEM_MSG="🔄 Ralph iteration $NEXT_ITERATION | To stop: output <promise>$COMPLETION_PROMISE</promise> (ONLY when statement is TRUE - do not lie to exit!)"
|
|
161
|
+
else
|
|
162
|
+
SYSTEM_MSG="🔄 Ralph iteration $NEXT_ITERATION | No completion promise set - loop runs infinitely"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# Output JSON to block the stop and feed prompt back
|
|
166
|
+
# The "reason" field contains the prompt that will be sent back to Claude
|
|
167
|
+
jq -n \
|
|
168
|
+
--arg prompt "$PROMPT_TEXT" \
|
|
169
|
+
--arg msg "$SYSTEM_MSG" \
|
|
170
|
+
'{
|
|
171
|
+
"decision": "block",
|
|
172
|
+
"reason": $prompt,
|
|
173
|
+
"systemMessage": $msg
|
|
174
|
+
}'
|
|
175
|
+
|
|
176
|
+
# Exit 0 for successful hook execution
|
|
177
|
+
exit 0
|