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.
Files changed (57) hide show
  1. package/.claude/skills/idea/SKILL.md +56 -0
  2. package/.claude/skills/loopgram/SKILL.md +19 -0
  3. package/.claude/skills/prd/SKILL.md +2 -0
  4. package/README.md +1 -0
  5. package/bin/ralph.sh +17 -11
  6. package/dist/loopgram/claude.d.ts +18 -0
  7. package/dist/loopgram/claude.d.ts.map +1 -0
  8. package/dist/loopgram/claude.js +89 -0
  9. package/dist/loopgram/claude.js.map +1 -0
  10. package/dist/loopgram/context-search.d.ts +26 -0
  11. package/dist/loopgram/context-search.d.ts.map +1 -0
  12. package/dist/loopgram/context-search.js +175 -0
  13. package/dist/loopgram/context-search.js.map +1 -0
  14. package/dist/loopgram/conversation.d.ts +39 -0
  15. package/dist/loopgram/conversation.d.ts.map +1 -0
  16. package/dist/loopgram/conversation.js +158 -0
  17. package/dist/loopgram/conversation.js.map +1 -0
  18. package/dist/loopgram/index.d.ts +3 -0
  19. package/dist/loopgram/index.d.ts.map +1 -0
  20. package/dist/loopgram/index.js +246 -0
  21. package/dist/loopgram/index.js.map +1 -0
  22. package/dist/loopgram/loop-monitor.d.ts +16 -0
  23. package/dist/loopgram/loop-monitor.d.ts.map +1 -0
  24. package/dist/loopgram/loop-monitor.js +149 -0
  25. package/dist/loopgram/loop-monitor.js.map +1 -0
  26. package/dist/loopgram/loop-runner.d.ts +28 -0
  27. package/dist/loopgram/loop-runner.d.ts.map +1 -0
  28. package/dist/loopgram/loop-runner.js +157 -0
  29. package/dist/loopgram/loop-runner.js.map +1 -0
  30. package/dist/loopgram/prd-generator.d.ts +37 -0
  31. package/dist/loopgram/prd-generator.d.ts.map +1 -0
  32. package/dist/loopgram/prd-generator.js +134 -0
  33. package/dist/loopgram/prd-generator.js.map +1 -0
  34. package/dist/loopgram/saver.d.ts +9 -0
  35. package/dist/loopgram/saver.d.ts.map +1 -0
  36. package/dist/loopgram/saver.js +35 -0
  37. package/dist/loopgram/saver.js.map +1 -0
  38. package/dist/loopgram/types.d.ts +37 -0
  39. package/dist/loopgram/types.d.ts.map +1 -0
  40. package/dist/loopgram/types.js +5 -0
  41. package/dist/loopgram/types.js.map +1 -0
  42. package/package.json +6 -2
  43. package/ralph/hooks/common.sh +89 -0
  44. package/ralph/hooks/warn-debug.sh +14 -32
  45. package/ralph/hooks/warn-empty-catch.sh +13 -29
  46. package/ralph/hooks/warn-secrets.sh +19 -37
  47. package/ralph/hooks/warn-urls.sh +17 -33
  48. package/ralph/loop.sh +5 -2
  49. package/ralph/prd-check.sh +35 -8
  50. package/ralph/setup/quick-setup.sh +25 -12
  51. package/ralph/setup/ui.sh +0 -42
  52. package/ralph/setup.sh +71 -46
  53. package/ralph/utils.sh +167 -31
  54. package/templates/config/fastmcp.json +6 -1
  55. package/templates/config/fullstack.json +8 -0
  56. package/templates/config/node.json +8 -0
  57. 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://
@@ -61,7 +61,12 @@
61
61
  "serverModule": "",
62
62
  "tools": [],
63
63
  "resources": [],
64
- "prompts": []
64
+ "prompts": [],
65
+ "playwright": {
66
+ "browser": "chromium",
67
+ "headless": true,
68
+ "viewport": "1280x720"
69
+ }
65
70
  },
66
71
 
67
72
  "playwright": {
@@ -64,6 +64,14 @@
64
64
  "baseUrl": "http://localhost:3000"
65
65
  },
66
66
 
67
+ "mcp": {
68
+ "playwright": {
69
+ "browser": "chromium",
70
+ "headless": true,
71
+ "viewport": "1280x720"
72
+ }
73
+ },
74
+
67
75
  "verification": {
68
76
  "codeReviewEnabled": true,
69
77
  "browserEnabled": true,
@@ -62,6 +62,14 @@
62
62
  "baseUrl": "http://localhost:3000"
63
63
  },
64
64
 
65
+ "mcp": {
66
+ "playwright": {
67
+ "browser": "chromium",
68
+ "headless": true,
69
+ "viewport": "1280x720"
70
+ }
71
+ },
72
+
65
73
  "verification": {
66
74
  "codeReviewEnabled": true,
67
75
  "browserEnabled": true,
@@ -62,6 +62,14 @@
62
62
  "baseUrl": "http://localhost:8000"
63
63
  },
64
64
 
65
+ "mcp": {
66
+ "playwright": {
67
+ "browser": "chromium",
68
+ "headless": true,
69
+ "viewport": "1280x720"
70
+ }
71
+ },
72
+
65
73
  "verification": {
66
74
  "codeReviewEnabled": true,
67
75
  "browserEnabled": true,