agentic-loop 3.13.0 → 3.14.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/.claude/skills/idea/SKILL.md +56 -0
- package/.claude/skills/loopgram/SKILL.md +19 -0
- package/.claude/skills/prd/SKILL.md +2 -0
- package/README.md +1 -0
- package/bin/ralph.sh +17 -11
- package/dist/loopgram/claude.d.ts +18 -0
- package/dist/loopgram/claude.d.ts.map +1 -0
- package/dist/loopgram/claude.js +89 -0
- package/dist/loopgram/claude.js.map +1 -0
- package/dist/loopgram/context-search.d.ts +26 -0
- package/dist/loopgram/context-search.d.ts.map +1 -0
- package/dist/loopgram/context-search.js +175 -0
- package/dist/loopgram/context-search.js.map +1 -0
- package/dist/loopgram/conversation.d.ts +39 -0
- package/dist/loopgram/conversation.d.ts.map +1 -0
- package/dist/loopgram/conversation.js +158 -0
- package/dist/loopgram/conversation.js.map +1 -0
- package/dist/loopgram/index.d.ts +3 -0
- package/dist/loopgram/index.d.ts.map +1 -0
- package/dist/loopgram/index.js +246 -0
- package/dist/loopgram/index.js.map +1 -0
- package/dist/loopgram/loop-monitor.d.ts +16 -0
- package/dist/loopgram/loop-monitor.d.ts.map +1 -0
- package/dist/loopgram/loop-monitor.js +149 -0
- package/dist/loopgram/loop-monitor.js.map +1 -0
- package/dist/loopgram/loop-runner.d.ts +28 -0
- package/dist/loopgram/loop-runner.d.ts.map +1 -0
- package/dist/loopgram/loop-runner.js +157 -0
- package/dist/loopgram/loop-runner.js.map +1 -0
- package/dist/loopgram/prd-generator.d.ts +37 -0
- package/dist/loopgram/prd-generator.d.ts.map +1 -0
- package/dist/loopgram/prd-generator.js +134 -0
- package/dist/loopgram/prd-generator.js.map +1 -0
- package/dist/loopgram/saver.d.ts +9 -0
- package/dist/loopgram/saver.d.ts.map +1 -0
- package/dist/loopgram/saver.js +35 -0
- package/dist/loopgram/saver.js.map +1 -0
- package/dist/loopgram/types.d.ts +37 -0
- package/dist/loopgram/types.d.ts.map +1 -0
- package/dist/loopgram/types.js +5 -0
- package/dist/loopgram/types.js.map +1 -0
- package/package.json +6 -2
- package/ralph/hooks/common.sh +89 -0
- package/ralph/hooks/warn-debug.sh +14 -32
- package/ralph/hooks/warn-empty-catch.sh +13 -29
- package/ralph/hooks/warn-secrets.sh +19 -37
- package/ralph/hooks/warn-urls.sh +17 -33
- package/ralph/loop.sh +5 -2
- package/ralph/prd-check.sh +35 -8
- package/ralph/setup/quick-setup.sh +25 -12
- package/ralph/setup/ui.sh +0 -42
- package/ralph/setup.sh +71 -46
- package/ralph/utils.sh +167 -31
- package/templates/config/fastmcp.json +6 -1
- package/templates/config/fullstack.json +8 -0
- package/templates/config/node.json +8 -0
- package/templates/config/python.json +8 -0
package/ralph/utils.sh
CHANGED
|
@@ -77,36 +77,6 @@ print_success() { echo -e "${GREEN}$1${NC}"; }
|
|
|
77
77
|
print_warning() { echo -e "${YELLOW}$1${NC}"; }
|
|
78
78
|
print_info() { echo -e "${BLUE}$1${NC}"; }
|
|
79
79
|
|
|
80
|
-
# Require a file to exist
|
|
81
|
-
require_file() {
|
|
82
|
-
local file="$1"
|
|
83
|
-
local msg="${2:-File not found: $file}"
|
|
84
|
-
if [[ ! -f "$file" ]]; then
|
|
85
|
-
print_error "$msg"
|
|
86
|
-
exit 1
|
|
87
|
-
fi
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# Require a directory to exist
|
|
91
|
-
require_dir() {
|
|
92
|
-
local dir="$1"
|
|
93
|
-
local msg="${2:-Directory not found: $dir}"
|
|
94
|
-
if [[ ! -d "$dir" ]]; then
|
|
95
|
-
print_error "$msg"
|
|
96
|
-
exit 1
|
|
97
|
-
fi
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
# Require a command to be available
|
|
101
|
-
require_command() {
|
|
102
|
-
local cmd="$1"
|
|
103
|
-
local msg="${2:-Command not found: $cmd}"
|
|
104
|
-
if ! command -v "$cmd" &>/dev/null; then
|
|
105
|
-
print_error "$msg"
|
|
106
|
-
exit 1
|
|
107
|
-
fi
|
|
108
|
-
}
|
|
109
|
-
|
|
110
80
|
# Check all required dependencies
|
|
111
81
|
check_dependencies() {
|
|
112
82
|
local missing=()
|
|
@@ -166,6 +136,172 @@ get_config() {
|
|
|
166
136
|
echo "$default"
|
|
167
137
|
}
|
|
168
138
|
|
|
139
|
+
# Get a field from a story in prd.json
|
|
140
|
+
# Usage: get_story_field "STORY-001" ".type" "general"
|
|
141
|
+
get_story_field() {
|
|
142
|
+
local story_id="$1"
|
|
143
|
+
local field="$2"
|
|
144
|
+
local default="${3:-}"
|
|
145
|
+
local prd="$RALPH_DIR/prd.json"
|
|
146
|
+
|
|
147
|
+
if [[ -f "$prd" ]]; then
|
|
148
|
+
local value
|
|
149
|
+
value=$(jq -r --arg id "$story_id" ".stories[] | select(.id==\$id) | $field // empty" "$prd" 2>/dev/null)
|
|
150
|
+
if [[ -n "$value" && "$value" != "null" ]]; then
|
|
151
|
+
echo "$value"
|
|
152
|
+
return
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
echo "$default"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# Clear a failure log file
|
|
159
|
+
# Usage: clear_failure_log "lint" # clears last_lint_failure.log
|
|
160
|
+
clear_failure_log() {
|
|
161
|
+
local log_name="$1"
|
|
162
|
+
rm -f "$RALPH_DIR/last_${log_name}_failure.log"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Append content to a failure log file
|
|
166
|
+
# Usage: log_failure "lint" "Error details here"
|
|
167
|
+
log_failure() {
|
|
168
|
+
local log_name="$1"
|
|
169
|
+
local content="$2"
|
|
170
|
+
echo "$content" >> "$RALPH_DIR/last_${log_name}_failure.log"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Deep merge user config with project config
|
|
174
|
+
# User config provides defaults, project config overrides
|
|
175
|
+
_merge_user_config() {
|
|
176
|
+
local project_config="$RALPH_DIR/config.json"
|
|
177
|
+
local user_config="$HOME/.config/ralph/config.json"
|
|
178
|
+
|
|
179
|
+
# Skip if no user config
|
|
180
|
+
[[ ! -f "$user_config" ]] && return 0
|
|
181
|
+
|
|
182
|
+
# Skip if no project config
|
|
183
|
+
[[ ! -f "$project_config" ]] && return 0
|
|
184
|
+
|
|
185
|
+
# Deep merge: user config * project config (project wins)
|
|
186
|
+
local merged
|
|
187
|
+
merged=$(jq -s '.[0] * .[1]' "$user_config" "$project_config" 2>/dev/null)
|
|
188
|
+
|
|
189
|
+
if [[ -n "$merged" && "$merged" != "null" ]]; then
|
|
190
|
+
echo "$merged" > "$project_config"
|
|
191
|
+
fi
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Manage user-level Ralph configuration
|
|
195
|
+
ralph_config() {
|
|
196
|
+
local cmd="${1:-show}"
|
|
197
|
+
local user_config_dir="$HOME/.config/ralph"
|
|
198
|
+
local user_config="$user_config_dir/config.json"
|
|
199
|
+
|
|
200
|
+
case "$cmd" in
|
|
201
|
+
show)
|
|
202
|
+
echo "=== User Config ==="
|
|
203
|
+
echo "Location: $user_config"
|
|
204
|
+
if [[ -f "$user_config" ]]; then
|
|
205
|
+
jq '.' "$user_config"
|
|
206
|
+
else
|
|
207
|
+
echo "(not configured - run 'ralph config init')"
|
|
208
|
+
fi
|
|
209
|
+
echo ""
|
|
210
|
+
echo "=== Global Hooks ==="
|
|
211
|
+
if [[ -d "$user_config_dir/hooks" ]]; then
|
|
212
|
+
ls -1 "$user_config_dir/hooks" 2>/dev/null || echo "(none)"
|
|
213
|
+
else
|
|
214
|
+
echo "(none)"
|
|
215
|
+
fi
|
|
216
|
+
;;
|
|
217
|
+
|
|
218
|
+
init)
|
|
219
|
+
mkdir -p "$user_config_dir/hooks" "$user_config_dir/templates/config"
|
|
220
|
+
if [[ ! -f "$user_config" ]]; then
|
|
221
|
+
echo '{}' > "$user_config"
|
|
222
|
+
echo "Created $user_config"
|
|
223
|
+
else
|
|
224
|
+
echo "User config already exists: $user_config"
|
|
225
|
+
fi
|
|
226
|
+
echo ""
|
|
227
|
+
echo "Directories created:"
|
|
228
|
+
echo " $user_config_dir/hooks/ - Add global hooks here"
|
|
229
|
+
echo " $user_config_dir/templates/ - Override default templates"
|
|
230
|
+
;;
|
|
231
|
+
|
|
232
|
+
get)
|
|
233
|
+
# ralph config get commands.test
|
|
234
|
+
local key="$2"
|
|
235
|
+
if [[ -z "$key" ]]; then
|
|
236
|
+
echo "Usage: ralph config get <key>"
|
|
237
|
+
echo "Example: ralph config get commands.test"
|
|
238
|
+
return 1
|
|
239
|
+
fi
|
|
240
|
+
local value
|
|
241
|
+
value=$(jq -r ".$key // empty" "$user_config" 2>/dev/null)
|
|
242
|
+
if [[ -n "$value" && "$value" != "null" ]]; then
|
|
243
|
+
echo "$value"
|
|
244
|
+
else
|
|
245
|
+
echo "(not set)"
|
|
246
|
+
fi
|
|
247
|
+
;;
|
|
248
|
+
|
|
249
|
+
set)
|
|
250
|
+
# ralph config set commands.test "uv run pytest"
|
|
251
|
+
local key="$2"
|
|
252
|
+
local value="$3"
|
|
253
|
+
if [[ -z "$key" || -z "$value" ]]; then
|
|
254
|
+
echo "Usage: ralph config set <key> <value>"
|
|
255
|
+
echo "Example: ralph config set commands.test 'uv run pytest'"
|
|
256
|
+
return 1
|
|
257
|
+
fi
|
|
258
|
+
mkdir -p "$user_config_dir"
|
|
259
|
+
[[ ! -f "$user_config" ]] && echo '{}' > "$user_config"
|
|
260
|
+
|
|
261
|
+
# Build jq path from dot notation: commands.test -> .commands.test
|
|
262
|
+
local jq_path=".$key"
|
|
263
|
+
jq --arg v "$value" "$jq_path = \$v" "$user_config" > "${user_config}.tmp" \
|
|
264
|
+
&& mv "${user_config}.tmp" "$user_config"
|
|
265
|
+
echo "Set $key = $value"
|
|
266
|
+
;;
|
|
267
|
+
|
|
268
|
+
unset)
|
|
269
|
+
# ralph config unset commands.test
|
|
270
|
+
local key="$2"
|
|
271
|
+
if [[ -z "$key" ]]; then
|
|
272
|
+
echo "Usage: ralph config unset <key>"
|
|
273
|
+
return 1
|
|
274
|
+
fi
|
|
275
|
+
[[ ! -f "$user_config" ]] && return 0
|
|
276
|
+
local jq_path=".$key"
|
|
277
|
+
jq "del($jq_path)" "$user_config" > "${user_config}.tmp" \
|
|
278
|
+
&& mv "${user_config}.tmp" "$user_config"
|
|
279
|
+
echo "Removed $key"
|
|
280
|
+
;;
|
|
281
|
+
|
|
282
|
+
path)
|
|
283
|
+
echo "$user_config_dir"
|
|
284
|
+
;;
|
|
285
|
+
|
|
286
|
+
*)
|
|
287
|
+
echo "Usage: ralph config <command>"
|
|
288
|
+
echo ""
|
|
289
|
+
echo "Commands:"
|
|
290
|
+
echo " show Show current user config"
|
|
291
|
+
echo " init Initialize user config directory"
|
|
292
|
+
echo " get <key> Get a config value"
|
|
293
|
+
echo " set <key> <v> Set a config value"
|
|
294
|
+
echo " unset <key> Remove a config value"
|
|
295
|
+
echo " path Print config directory path"
|
|
296
|
+
echo ""
|
|
297
|
+
echo "Examples:"
|
|
298
|
+
echo " ralph config init"
|
|
299
|
+
echo " ralph config set commands.test 'uv run pytest'"
|
|
300
|
+
echo " ralph config get commands.test"
|
|
301
|
+
;;
|
|
302
|
+
esac
|
|
303
|
+
}
|
|
304
|
+
|
|
169
305
|
# Cross-platform timeout (macOS needs gtimeout from coreutils)
|
|
170
306
|
run_with_timeout() {
|
|
171
307
|
local seconds="$1"
|
|
@@ -313,7 +449,7 @@ validate_command() {
|
|
|
313
449
|
}
|
|
314
450
|
|
|
315
451
|
# Validate a URL is safe (http/https only, no internal IPs in production)
|
|
316
|
-
validate_url() {
|
|
452
|
+
validate_url() { # public-api
|
|
317
453
|
local url="$1"
|
|
318
454
|
|
|
319
455
|
# Must start with http:// or https://
|