@pageai/ralph-loop 1.0.0

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 (120) hide show
  1. package/.agent/PROMPT.md +58 -0
  2. package/.agent/STEERING.md +3 -0
  3. package/.agent/logs/LOG.md +13 -0
  4. package/.agent/prd/.gitkeep +0 -0
  5. package/.agent/screenshots/.gitkeep +0 -0
  6. package/.agent/skills/component-refactoring/SKILL.md +247 -0
  7. package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
  8. package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
  9. package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
  10. package/.agent/skills/e2e-tester/SKILL.md +595 -0
  11. package/.agent/skills/frontend-code-review/SKILL.md +73 -0
  12. package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
  13. package/.agent/skills/frontend-code-review/references/performance.md +36 -0
  14. package/.agent/skills/frontend-testing/SKILL.md +316 -0
  15. package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
  16. package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
  17. package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
  18. package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
  19. package/.agent/skills/frontend-testing/references/checklist.md +188 -0
  20. package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
  21. package/.agent/skills/frontend-testing/references/mocking.md +289 -0
  22. package/.agent/skills/frontend-testing/references/workflow.md +265 -0
  23. package/.agent/skills/prd-creator/JSON.md +613 -0
  24. package/.agent/skills/prd-creator/PRD.md +196 -0
  25. package/.agent/skills/prd-creator/SKILL.md +143 -0
  26. package/.agent/skills/skill-creator/SKILL.md +355 -0
  27. package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
  28. package/.agent/skills/skill-creator/references/workflows.md +28 -0
  29. package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
  30. package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
  31. package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
  32. package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
  33. package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  34. package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
  35. package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  36. package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  37. package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
  38. package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  39. package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  40. package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  41. package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  42. package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  43. package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  44. package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  45. package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  46. package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  47. package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
  48. package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  49. package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  50. package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  51. package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  52. package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  53. package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  54. package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  55. package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  56. package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  57. package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  58. package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  59. package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  60. package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  61. package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  62. package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  63. package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  64. package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  65. package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  66. package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  67. package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  68. package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  69. package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  70. package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  71. package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  72. package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  73. package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  74. package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  75. package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
  76. package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
  77. package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  78. package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
  79. package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
  80. package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
  81. package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
  82. package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
  83. package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
  84. package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
  85. package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
  86. package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
  87. package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
  88. package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
  89. package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
  90. package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
  91. package/.agent/tasks/.gitkeep +0 -0
  92. package/.agent/tasks.json +1 -0
  93. package/.claude/agents/code-reviewer.md +172 -0
  94. package/.claude/commands/aw.md +50 -0
  95. package/.claude/hooks/play-sound.js +87 -0
  96. package/.claude/hooks/pre-tool-use.js +40 -0
  97. package/.claude/settings.json +54 -0
  98. package/.claude/settings.local.json +13 -0
  99. package/.mcp.json +31 -0
  100. package/AGENTS.md +44 -0
  101. package/CLAUDE.md +1 -0
  102. package/README.md +236 -0
  103. package/bin/cli.js +156 -0
  104. package/bin/lib/copy.js +149 -0
  105. package/bin/lib/display.js +137 -0
  106. package/package.json +65 -0
  107. package/ralph.sh +333 -0
  108. package/scripts/lib/args.sh +44 -0
  109. package/scripts/lib/cleanup.sh +53 -0
  110. package/scripts/lib/constants.sh +25 -0
  111. package/scripts/lib/display.sh +196 -0
  112. package/scripts/lib/logging.sh +30 -0
  113. package/scripts/lib/notify.sh +41 -0
  114. package/scripts/lib/output.sh +147 -0
  115. package/scripts/lib/preflight.sh +57 -0
  116. package/scripts/lib/preview.sh +77 -0
  117. package/scripts/lib/promise.sh +76 -0
  118. package/scripts/lib/spinner.sh +85 -0
  119. package/scripts/lib/terminal.sh +57 -0
  120. package/scripts/lib/timing.sh +223 -0
@@ -0,0 +1,196 @@
1
+ #!/bin/bash
2
+ # Display module for ralph.sh
3
+ # UI elements, ASCII art, and help display
4
+ # Dependencies: constants.sh, timing.sh
5
+
6
+ # Display BLOCKED message with reason and resume instructions
7
+ # Usage: display_blocked_message "reason" iteration_number
8
+ display_blocked_message() {
9
+ local reason="$1"
10
+ local iteration="$2"
11
+
12
+ echo ""
13
+ echo -e "${RD}░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░${R}"
14
+ echo -e " 🚫 ${RD}Agent is BLOCKED${R}"
15
+ echo -e "${RD}░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░${R}"
16
+ echo ""
17
+ echo -e " ${Y}Reason:${R}"
18
+ echo -e " $reason"
19
+ echo ""
20
+ echo -e " ${C}How to resume:${R}"
21
+ echo -e " 1. Resolve the blocking issue described above"
22
+ echo -e " 2. Run ${GR}./ralph.sh${R} to continue from where you left off"
23
+ echo ""
24
+ echo -e " ${G}Stopped at iteration ${Y}$iteration${R}"
25
+ echo ""
26
+ }
27
+
28
+ # Display DECIDE message with question and resume instructions
29
+ # Usage: display_decide_message "question" iteration_number
30
+ display_decide_message() {
31
+ local question="$1"
32
+ local iteration="$2"
33
+
34
+ echo ""
35
+ echo -e "${M}░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░${R}"
36
+ echo -e " ❓ ${M}Agent needs a DECISION${R}"
37
+ echo -e "${M}░░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░${R}"
38
+ echo ""
39
+ echo -e " ${Y}Question:${R}"
40
+ echo -e " $question"
41
+ echo ""
42
+ echo -e " ${C}How to answer and resume:${R}"
43
+ echo -e " 1. Make a decision about the question above"
44
+ echo -e " 2. Update the relevant files or configuration"
45
+ echo -e " 3. Run ${GR}./ralph.sh${R} to continue with your decision"
46
+ echo ""
47
+ echo -e " ${G}Stopped at iteration ${Y}$iteration${R}"
48
+ echo ""
49
+ }
50
+
51
+ # Ralph ASCII art and catchphrases
52
+ show_ralph() {
53
+
54
+ local catchphrases=(
55
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
56
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm helping!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
57
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm doing my best!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
58
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm in danger!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
59
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm learnding!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
60
+ "■▒▒▒▒▒▒▒My cat's breath smells like cat food.▒▒▒▒▒▒▒▒▒■▒▒▓■"
61
+ "■▒▒▒▒▒▒▒▒Me fail English? That's unpossible!▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
62
+ "■▒▒▒▒▒▒▒▒▒I'm asking Claude to cook pasta!▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
63
+ "■▒▒▒▒▒▒▒▒▒▒I found a moon rock in my nose!▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
64
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒It tastes like burning!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
65
+ "■▒▒▒▒▒▒When I grow up, I want to be a computer!▒▒▒▒▒▒▒■▒▒▓■"
66
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm a develotron!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
67
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm helpding AI!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
68
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm essential!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
69
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
70
+ )
71
+
72
+ local random_index=$((RANDOM % 15))
73
+ local phrase="${catchphrases[$random_index]}"
74
+
75
+ echo ""
76
+ echo -e "${Y}"
77
+ cat << 'RALPH'
78
+
79
+ ██████╗ █████╗ ██╗ ██████╗ ██╗ ██╗
80
+ ██╔══██╗██╔══██╗██║ ██╔══██╗██║ ██║
81
+ ██████╔╝███████║██║ ██████╔╝███████║
82
+ ██╔══██╗██╔══██║██║ ██╔═══╝ ██╔══██║
83
+ ██║ ██║██║ ██║███████╗██║ ██║ ██║
84
+ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝
85
+
86
+ ██╗ ██████╗ ██████╗ ██████╗
87
+ ██║ ██╔═══██╗██╔═══██╗██╔══██╗
88
+ ██║ ██║ ██║██║ ██║██████╔╝
89
+ ██║ ██║ ██║██║ ██║██╔═══╝
90
+ ███████╗╚██████╔╝╚██████╔╝██║
91
+ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝
92
+
93
+ ■■■■■■■■■■■■■■■■■■■■■■■■■■■▓▓■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
94
+ ■■■■■■■■■■■■■■■■▓▒▓▒▓▒▒▓▒▒▓▢▒▒▓▒▓▒▓▓■■■■■■■■■■■■■■■■■■■■■■■
95
+ ■■■■■■■■■■■▓▓▓▒▓▒▒▓▒▒▓▒▒▓▒▢▓▒▢▓▢▒▓▒▒▓▒▓▓▓▓■■■■■■■■■■■■■■■■■
96
+ ■■■■■■■■■▒▢▒▒▓▒▢▓▒▢▒▓▢▒▓▢▢▒▒▢▒▓▢▢▒▒▢▢▓▒▒▓▒▓▒■■■■■■■■■■■■■■■
97
+ ■■■■■■■■■▓▒▒▓▢▒▒▒▢▒▓▢▢▓▢▢▢▓▢▢▒▒▢▢▢▓▒▢▒▒▒▒▓▒▓▒▒▓▓■■■■■■■■■■■
98
+ ■■■■■■■■▓▢▒▓▢▢▓▒▢▒▓▢▢▓▒▢▢▢▒▢▢▒▒▢▢▢▒▒▢▢▒▒▢▒▓▢▒▒▒▓■■■■■■■■■■■
99
+ ■■■■■■■▓▒▒▓▢▢▓▒▢▢▓▢▢▢▒▢▢▢▢▢▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▒▓■■■■■■■■■■
100
+ ■■■■■■▓▒▒▓▢▢▒▓▢▢▒▒▢▢▢▢▢▒▒▢ ▢▒▒▢▢▢▢▢▢▒▒▢ ▢▒▒▒■■■■■■■■■■
101
+ ■■■■■■▓▢▓▒▢▢▓▒▢▢▢▢▢▢▢▢▒▒ ▢▒▢▢▢▢▒ ▢▒▓■■■■■■■■■
102
+ ■■■■■▓▒▒▓▢▢▢▓▢▢▢▢▢▢▢▢▢▒ ▓👁️▓ ▒▢▢▢▢▒ ▓👁️▓ ▢▒▓■■■■■■■■■
103
+ ■■■■▓▒▒▒▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▓ ▒▒▢▢▢▢▒▒▢ ▢▒▒▓■■■■■■■■■
104
+ ■■■■▢▒▓▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▓▒ ▢▓▒▢▢▒▢▢▒▒▓▢▢▢▢▢▢▢▒▒▓■■■■■■■■■
105
+ ■■■■▓▢▒▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▒▒▒▒▒▢▢▢▢▢▢▢▢▢▢▒▒▓■■■■■■■■
106
+ ■■■■▓▢▒▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▒▒▒▒▒▒▒▒▒▢▢▢▢▢▢▢▢▢▒▒▓■■■■■■■
107
+ ■■■■■▓▓▒▒▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▓▓▒▢▒▓▒▢▒▒▓▢▢▢▢▢▢▢▢▢▢▒▒■■■■■■■■
108
+ ■■■■■▓▓▒▒▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▓▓▒▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▒■■■■■■■■
109
+ ■■■■■■■■▓▒▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▒▓▒▢▢▒▒▓▒▢▢▢▢▢▢▢▢▢▢▢▢▒▒▒▓■■■■■■
110
+ ■■■■■■■■▓■▒▒▢▢▢▢▢▢▢▢▢▢▢▒▒▢▢▓▒▢▢▢▒▓▓▓▓▒▒▒▢▢▢▢▢▢▢▢▒▒▒▒▓■■■■■■
111
+ ■■■■■■■■■■■■▒▢▢▢▢▢▢▢▢▢▢▓▓■■▒▢▢▢▢▒▒▢▢▢▒▓▒▒▢▢▢▒▒▒▒■■■■■■■■■■■
112
+ ■■■■■■■■■■▒▒▒▓▒▒▢▢▢▢▢▢▢▢▢▢▓▒▢▢▢▢▢▢▒▒▓▒▒▓▓▒▒▒▓■■■■■■■■■■■■■■
113
+ ■■■■■■■■■▓▒▒▒▒▒▒▒▓▓▒▢▢▢▢▢▢▓▒▢▢▢▢▢▢▢▢▢▢▢▒▓▒▒▓■■■■■■■■■■■■■■■
114
+ ■■■■■■■■■▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▓▒▢▢▢▢▢▢▢▒▓▒▓▓▓▒▓■■■■■■■■■■■■■■
115
+ ■■■■■■▓▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▓▒▢▢▢▒▒▓▒▒▓▓▒▓▓▓■■■■■■■■■■■■
116
+ ■■■■■▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▓▒▒▒▓▓■▒▒▓■■■■■■■■■■■
117
+ ■■■▓■▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▓▒▒▓▓▒▒▒▒▓▓▓■■■■■■■■■■
118
+ ■■■■■▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒■■■■■■■■■
119
+ ■■■■■▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒■■■■■■■■
120
+ ■■■▓▢▢▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓■■■■■■■
121
+ ■■▓▢▢▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓■■■■■
122
+ ■▓▒▢▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓■■■■
123
+ ■▓▢▢▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▓■■■
124
+ ■▓▢▢▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓■▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▓■■
125
+ ■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▓■■
126
+ RALPH
127
+
128
+ echo -e "$phrase"
129
+ echo -e "■■▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▓■${R}"
130
+ echo -e "═══════════════════════════════════════════════════════════"
131
+ echo -e " Ralph Wiggum Loop ・ Long-running AI agents"
132
+ }
133
+
134
+ # Show help and instructions
135
+ show_help() {
136
+ show_ralph
137
+ echo ""
138
+ echo -e "${Y}Usage:${R} ./ralph.sh [options] [max_iterations]"
139
+ echo ""
140
+ echo -e "${Y}Options:${R}"
141
+ echo " --max-iterations N, -n N Set maximum iterations (default: 10)"
142
+ echo " --once Run exactly 1 iteration (overrides --max-iterations)"
143
+ echo " --help, -h Show this help message and exit"
144
+ echo ""
145
+ echo -e "${Y}Arguments:${R}"
146
+ echo " max_iterations Maximum number of iterations (positional, default: 10)"
147
+ echo ""
148
+ echo -e "${Y}Examples:${R}"
149
+ echo " ./ralph.sh Run with default 10 iterations"
150
+ echo " ./ralph.sh 5 Run with 5 iterations max"
151
+ echo " ./ralph.sh -n 5 Run with 5 iterations max"
152
+ echo " ./ralph.sh --max-iterations 5 Same as above"
153
+ echo " ./ralph.sh --once Run exactly 1 iteration"
154
+ echo ""
155
+ echo -e "${Y}Files:${R}"
156
+ echo " 📁 .agent/history/ Iteration output logs"
157
+ echo " 📋 .agent/logs/LOG.md Progress log file"
158
+ echo " 📄 .agent/prd/PRD.md PRD file with task definitions"
159
+ echo " 📄 .agent/tasks/ Detailed task descriptions"
160
+ echo " 📝 .agent/PROMPT.md Prompt sent to Claude each iteration"
161
+ echo " 📄 .agent/tasks.json Task lookup table"
162
+ echo ""
163
+ echo -e "${Y}Behavior:${R}"
164
+ echo " 🤔 Decides on what tasks to pick from .agent/tasks.json"
165
+ echo " 📋 Logs progress to .agent/logs/LOG.md"
166
+ echo " 🎉 Exits early if Claude outputs <promise>COMPLETE</promise>"
167
+ echo " 🖼️ Takes screenshots of progress"
168
+ echo ""
169
+ echo -e "${B}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}"
170
+ echo -e "${Y}📚 Getting Started:${R}"
171
+ echo -e "${B}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${R}"
172
+ echo ""
173
+ echo -e " ${C}Step 1:${R} Create a PRD using the prd-creator skill"
174
+ echo -e " ${G}Dump your requirements and ask AI to use the prd-creator skill${R}"
175
+ echo ""
176
+ echo -e " ${C}Step 2:${R} Ensure your .agent/ directory has the required files:"
177
+ echo " 📄 .agent/prd/PRD.md Your product requirements"
178
+ echo " 📄 .agent/prd/SUMMARY.md Short project overview"
179
+ echo " 📋 .agent/tasks.json Generated task list"
180
+ echo " 📁 .agent/tasks/ Individual task specs (TASK-{ID}.json)"
181
+ echo " 📝 .agent/PROMPT.md Agent instructions"
182
+ echo " 📋 .agent/logs/LOG.md Progress log (auto-created)"
183
+ echo ""
184
+ echo -e " ${C}Step 3:${R} Run Ralph!"
185
+ echo -e " ${G}./ralph.sh${R} # Start the agent loop"
186
+ echo ""
187
+ echo -e "${Y}🔄 How it works:${R}"
188
+ echo " Each iteration, Ralph will:"
189
+ echo " 1. Find the highest-priority incomplete task in tasks.json"
190
+ echo " 2. Work through the task steps in .agent/tasks/TASK-{ID}.json"
191
+ echo " 3. Run tests, linting, and type checking"
192
+ echo " 4. Update task status and commit changes"
193
+ echo " 5. Repeat until all tasks pass or max iterations reached"
194
+ echo ""
195
+ exit 0
196
+ }
@@ -0,0 +1,30 @@
1
+ #!/bin/bash
2
+ # Logging module for ralph.sh
3
+ # Consistent, colored logging for different message types.
4
+ # Dependencies: constants.sh
5
+ #
6
+ # Usage:
7
+ # log_info "Starting process..."
8
+ # log_success "Task completed"
9
+ # log_warn "This might take a while"
10
+ # log_error "Something went wrong"
11
+
12
+ # Log info message with blue [INFO] prefix
13
+ log_info() {
14
+ echo -e "${B}[INFO]${R} $1"
15
+ }
16
+
17
+ # Log success message with green [OK] prefix
18
+ log_success() {
19
+ echo -e "${GR}[OK]${R} $1"
20
+ }
21
+
22
+ # Log warning message with yellow [WARN] prefix
23
+ log_warn() {
24
+ echo -e "${Y}[WARN]${R} $1"
25
+ }
26
+
27
+ # Log error message with red [ERROR] prefix to stderr
28
+ log_error() {
29
+ echo -e "${RD}[ERROR]${R} $1" >&2
30
+ }
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # Notification module for ralph.sh
3
+ # Cross-platform sound and desktop notifications
4
+ # Dependencies: None
5
+
6
+ # Play notification sound cross-platform
7
+ # Usage: play_notification_sound
8
+ # Supports macOS, Linux (PulseAudio), Windows (WSL), with terminal bell fallback
9
+ play_notification_sound() {
10
+ (
11
+ # Try macOS first (afplay)
12
+ if command -v afplay &> /dev/null; then
13
+ afplay /System/Library/Sounds/Glass.aiff 2>/dev/null || true
14
+ # Try Linux (PulseAudio)
15
+ elif command -v paplay &> /dev/null; then
16
+ paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || true
17
+ # Try Windows/WSL (PowerShell)
18
+ elif command -v powershell.exe &> /dev/null; then
19
+ powershell.exe -Command "[System.Media.SystemSounds]::Asterisk.Play()" 2>/dev/null || true
20
+ fi
21
+ # Always try terminal bell as additional notification
22
+ echo -e '\a' 2>/dev/null || true
23
+ ) &
24
+ }
25
+
26
+ # Show desktop notification cross-platform
27
+ # Usage: show_notification "title" "message"
28
+ # Supports macOS (osascript), Linux (notify-send), fails silently on unsupported platforms
29
+ show_notification() {
30
+ local title="$1"
31
+ local message="$2"
32
+ (
33
+ # Try macOS (osascript)
34
+ if command -v osascript &> /dev/null; then
35
+ osascript -e "display notification \"$message\" with title \"$title\"" 2>/dev/null || true
36
+ # Try Linux (notify-send)
37
+ elif command -v notify-send &> /dev/null; then
38
+ notify-send "$title" "$message" 2>/dev/null || true
39
+ fi
40
+ ) &
41
+ }
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+ # Output module for ralph.sh
3
+ # JSON parsing and ANSI stripping utilities
4
+ # Dependencies: constants.sh, terminal.sh
5
+
6
+ # Parse JSON stream and extract text content
7
+ # Handles Agent's stream-json format
8
+ parse_json_content() {
9
+ local json_line="$1"
10
+ # Try to extract text content from various JSON formats
11
+ # For example, Claude stream-json outputs {"type":"content_block_delta","delta":{"text":"..."}}
12
+ # or {"type":"text","text":"..."} etc.
13
+
14
+ # Extract text from delta
15
+ local text=$(echo "$json_line" | grep -o '"text":"[^"]*"' | head -1 | sed 's/"text":"//;s/"$//')
16
+ if [ -n "$text" ]; then
17
+ # Unescape common JSON escapes
18
+ # JSON \n -> actual newline, \t -> actual tab, etc.
19
+ text=$(echo "$text" | sed 's/\\n/\'$'\n''/g; s/\\t/\'$'\t''/g; s/\\"/"/g; s/\\\\/\\/g')
20
+ echo "$text"
21
+ return
22
+ fi
23
+
24
+ # If it doesn't look like JSON, return as-is
25
+ if ! echo "$json_line" | grep -q '^{'; then
26
+ echo "$json_line"
27
+ fi
28
+ }
29
+
30
+ # Strip ANSI escape sequences and control characters from text
31
+ # Usage: clean_text=$(strip_ansi "$text")
32
+ # Handles:
33
+ # - CSI sequences: ESC[...m (colors), ESC[...H (cursor), ESC[?...h/l (modes)
34
+ # - OSC sequences: ESC]0;...(BEL or ESC\) for window titles
35
+ # - OSC-like sequences without ESC prefix (from script command)
36
+ # - Caret notation for control chars: ^@ through ^_ (from script command)
37
+ # - Other escapes: ESC followed by various characters
38
+ # - Control chars: backspace, BEL, carriage return, etc.
39
+ strip_ansi() {
40
+ local input="$1"
41
+ # First use sed to handle ESC sequences (must be done before tr removes ESC)
42
+ # Then use tr to remove remaining raw control characters
43
+ # tr removes: 0x00-0x08 (NUL through BS), 0x0B-0x0C (VT, FF), 0x0E-0x1A (SO through SUB),
44
+ # 0x1C-0x1F (FS through US) - excludes ESC (0x1B) for sed to process
45
+ # sed handles: ESC sequences, OSC-like patterns, caret notation
46
+ # Note: OSC pattern uses ^ anchor but also handles after caret removal via second pass
47
+ echo "$input" | sed \
48
+ -e 's/\x1b\[[0-9;?]*[A-Za-z]//g' \
49
+ -e 's/\x1b\][^\x07]*\x07//g' \
50
+ -e 's/\x1b\][^\x1b]*\x1b\\//g' \
51
+ -e 's/\x1b[()][AB012]//g' \
52
+ -e 's/\x1b[>=]//g' \
53
+ -e 's/\x1b.//g' \
54
+ -e 's/\^[][A-Z@\\^_]//g' \
55
+ -e 's/^0;[^]]*]//g' \
56
+ -e 's/<u0;//g' \
57
+ | tr -d '\000-\010\013\014\016-\032\034-\037' \
58
+ | sed -e 's/^0;[^]]*]//g'
59
+ }
60
+
61
+ # Strip ANSI from a file and write to output file
62
+ # Usage: strip_ansi_file "$input_file" "$output_file"
63
+ # First sed processes ESC sequences, then tr removes remaining control characters
64
+ strip_ansi_file() {
65
+ local input_file="$1"
66
+ local output_file="$2"
67
+ # First sed processes ESC sequences (before tr removes anything)
68
+ # Then tr removes remaining control characters (excluding newline 0x0A, CR 0x0D)
69
+ # tr range excludes ESC (0x1B = octal 033) which sed already handled
70
+ # Final sed pass cleans up OSC patterns that were hidden by control chars
71
+ sed \
72
+ -e 's/\x1b\[[0-9;?]*[A-Za-z]//g' \
73
+ -e 's/\x1b\][^\x07]*\x07//g' \
74
+ -e 's/\x1b\][^\x1b]*\x1b\\//g' \
75
+ -e 's/\x1b[()][AB012]//g' \
76
+ -e 's/\x1b[>=]//g' \
77
+ -e 's/\x1b.//g' \
78
+ -e 's/\^[][A-Z@\\^_]//g' \
79
+ -e 's/^0;[^]]*]//g' \
80
+ -e 's/<u0;//g' \
81
+ "$input_file" | tr -d '\000-\010\013\014\016-\032\034-\037' \
82
+ | sed -e 's/^0;[^]]*]//g' \
83
+ > "$output_file"
84
+ }
85
+
86
+ # Extract final summary from JSON stream output
87
+ # Looks for the result type message which contains the final output
88
+ extract_final_summary() {
89
+ local output_file="$1"
90
+ local result_line=""
91
+ local summary=""
92
+
93
+ # Look for the result type message in the JSON stream
94
+ if [ -f "$output_file" ]; then
95
+ result_line=$(grep '"type":"result"' "$output_file" 2>/dev/null | tail -1)
96
+
97
+ if [ -n "$result_line" ]; then
98
+ # Extract the result text using jq
99
+ if command -v jq &> /dev/null; then
100
+ summary=$(echo "$result_line" | jq -r '.result // ""' 2>/dev/null)
101
+ fi
102
+ fi
103
+ fi
104
+
105
+ echo "$summary"
106
+ }
107
+
108
+ # Display the final summary with simple separators
109
+ display_final_summary() {
110
+ local summary="$1"
111
+ local max_lines="${2:-15}" # Default to max 15 lines
112
+
113
+ if [ -z "$summary" ]; then
114
+ return
115
+ fi
116
+
117
+ # Display with simple separators
118
+ echo ""
119
+ echo -e "${C}─────────────────────────────────────────────────────────────────${R}"
120
+ echo -e "${Y}Iteration Summary${R}"
121
+ echo -e "${C}─────────────────────────────────────────────────────────────────${R}"
122
+
123
+ # Wrap and display lines (max 70 chars wide, max 15 lines)
124
+ local line_count=0
125
+ local width=70
126
+ while IFS= read -r line || [ -n "$line" ]; do
127
+ while [ ${#line} -gt $width ] && [ $line_count -lt $max_lines ]; do
128
+ # Find last space within width for word wrap
129
+ local cut_at=$width
130
+ local segment="${line:0:$width}"
131
+ local last_space="${segment% *}"
132
+ if [ "$last_space" != "$segment" ] && [ ${#last_space} -gt 20 ]; then
133
+ cut_at=${#last_space}
134
+ fi
135
+ echo "${line:0:$cut_at}"
136
+ line="${line:$cut_at}"
137
+ line="${line# }" # Remove leading space
138
+ ((line_count++))
139
+ done
140
+ if [ $line_count -lt $max_lines ] && [ -n "$line" ]; then
141
+ echo "$line"
142
+ ((line_count++))
143
+ fi
144
+ done <<< "$summary"
145
+
146
+ echo -e "${C}─────────────────────────────────────────────────────────────────${R}"
147
+ }
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ # Preflight module for ralph.sh
3
+ # Pre-flight checks before starting the main loop
4
+ # Dependencies: constants.sh, logging.sh
5
+ #
6
+ # Verify required files exist before starting the main loop.
7
+ # Required files cause script exit if missing.
8
+ # Optional files trigger a warning but allow continuation.
9
+
10
+ # Check if running inside a git repository
11
+ # Usage: check_git_repo
12
+ # Exits with code 1 if not in a git repository
13
+ check_git_repo() {
14
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
15
+ log_error "ralph.sh must be run inside a git repository"
16
+ exit 1
17
+ fi
18
+ }
19
+
20
+ # Ensure history directory exists for storing iteration logs
21
+ # Usage: check_history_dir
22
+ # Creates .agent/history/ directory if it doesn't exist
23
+ check_history_dir() {
24
+ mkdir -p "$HISTORY_DIR"
25
+ if [ ! -d "$HISTORY_DIR" ]; then
26
+ log_error "Failed to create history directory: $HISTORY_DIR"
27
+ exit 1
28
+ fi
29
+ }
30
+
31
+ # Check for required files and exit if missing, warn for optional files
32
+ # Usage: check_required_files
33
+ check_required_files() {
34
+ local missing_required=false
35
+
36
+ # Required files - exit if missing
37
+ if [ ! -f "$SCRIPT_DIR/.agent/tasks.json" ]; then
38
+ log_error "Required file missing: .agent/tasks.json"
39
+ missing_required=true
40
+ fi
41
+
42
+ if [ ! -f "$SCRIPT_DIR/.agent/PROMPT.md" ]; then
43
+ log_error "Required file missing: .agent/PROMPT.md"
44
+ missing_required=true
45
+ fi
46
+
47
+ # Exit if any required files are missing
48
+ if [ "$missing_required" = true ]; then
49
+ log_error "Please create the required files before running Ralph"
50
+ exit 1
51
+ fi
52
+
53
+ # Optional files - warn if missing but continue
54
+ if [ ! -f "$SCRIPT_DIR/.agent/prd/SUMMARY.md" ]; then
55
+ log_warn "Optional file missing: .agent/prd/SUMMARY.md"
56
+ fi
57
+ }
@@ -0,0 +1,77 @@
1
+ #!/bin/bash
2
+ # Preview module for ralph.sh
3
+ # Rolling preview buffer display
4
+ # Dependencies: constants.sh, terminal.sh
5
+
6
+ # Rolling preview settings
7
+ PREVIEW_LINES=50
8
+ PREVIEW_WIDTH=80
9
+ LINE_BUFFER=()
10
+ LINES_DISPLAYED=0
11
+ ANSI_SUPPORTED=true
12
+
13
+ # Initialize the rolling preview display
14
+ init_rolling_preview() {
15
+ LINE_BUFFER=()
16
+ LINES_DISPLAYED=0
17
+ PREVIEW_WIDTH=$(get_terminal_width)
18
+ }
19
+
20
+ # Add line to rolling buffer and update display
21
+ add_to_rolling_preview() {
22
+ local line="$1"
23
+
24
+ # Skip empty lines
25
+ [ -z "$line" ] && return
26
+
27
+ # Truncate to terminal width
28
+ line=$(truncate_line "$line" $PREVIEW_WIDTH)
29
+
30
+ # Add to buffer
31
+ LINE_BUFFER+=("$line")
32
+
33
+ # Keep only last PREVIEW_LINES
34
+ if [ ${#LINE_BUFFER[@]} -gt $PREVIEW_LINES ]; then
35
+ LINE_BUFFER=("${LINE_BUFFER[@]:1}")
36
+ fi
37
+
38
+ # Update display
39
+ if [ "$ANSI_SUPPORTED" = true ]; then
40
+ redraw_rolling_preview
41
+ else
42
+ # Fallback: just print the line
43
+ echo "$line"
44
+ fi
45
+ }
46
+
47
+ # Redraw the rolling preview using ANSI cursor control
48
+ redraw_rolling_preview() {
49
+ # Move cursor up to start of preview area
50
+ if [ $LINES_DISPLAYED -gt 0 ]; then
51
+ printf "\033[%dA" $LINES_DISPLAYED
52
+ fi
53
+
54
+ # Clear and redraw each line
55
+ local count=0
56
+ for line in "${LINE_BUFFER[@]}"; do
57
+ printf "\033[K%s\n" "$line"
58
+ count=$((count + 1))
59
+ done
60
+
61
+ # Update count of displayed lines
62
+ LINES_DISPLAYED=$count
63
+ }
64
+
65
+ # Clear the rolling preview area
66
+ clear_rolling_preview() {
67
+ if [ "$ANSI_SUPPORTED" = true ] && [ $LINES_DISPLAYED -gt 0 ]; then
68
+ # Move up and clear each line
69
+ printf "\033[%dA" $LINES_DISPLAYED
70
+ for ((i=0; i<$LINES_DISPLAYED; i++)); do
71
+ printf "\033[K\n"
72
+ done
73
+ printf "\033[%dA" $LINES_DISPLAYED
74
+ fi
75
+ LINE_BUFFER=()
76
+ LINES_DISPLAYED=0
77
+ }
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+ # Promise tags module for ralph.sh
3
+ # Semantic signals for agent communication
4
+ # Dependencies: None
5
+ #
6
+ # Promise tags allow the AI agent to communicate status to the loop controller.
7
+ # The script detects these tags in the agent's output to determine next actions.
8
+ #
9
+ # Tag Format: <promise>TYPE:content</promise>
10
+ #
11
+ # Available Tags:
12
+ # <promise>COMPLETE</promise> - All tasks finished successfully
13
+ # <promise>BLOCKED:reason</promise> - Agent is blocked and needs human help
14
+ # <promise>DECIDE:question</promise> - Agent needs human decision/clarification
15
+ #
16
+ # Examples:
17
+ # <promise>COMPLETE</promise>
18
+ # <promise>BLOCKED:Missing API credentials for external service</promise>
19
+ # <promise>DECIDE:Should we use REST or GraphQL for the new endpoint?</promise>
20
+
21
+ # Regex patterns for promise tags
22
+ PROMISE_COMPLETE_PATTERN='<promise>COMPLETE</promise>'
23
+ PROMISE_BLOCKED_PATTERN='<promise>BLOCKED:[^<]*</promise>'
24
+ PROMISE_DECIDE_PATTERN='<promise>DECIDE:[^<]*</promise>'
25
+
26
+ # Check if output contains a COMPLETE tag
27
+ # Usage: if has_complete_tag "$output"; then ...
28
+ has_complete_tag() {
29
+ local output="$1"
30
+ echo "$output" | grep -q "$PROMISE_COMPLETE_PATTERN"
31
+ }
32
+
33
+ # Check if output contains a BLOCKED tag
34
+ # Usage: if has_blocked_tag "$output"; then ...
35
+ has_blocked_tag() {
36
+ local output="$1"
37
+ echo "$output" | grep -qE "$PROMISE_BLOCKED_PATTERN"
38
+ }
39
+
40
+ # Check if output contains a DECIDE tag
41
+ # Usage: if has_decide_tag "$output"; then ...
42
+ has_decide_tag() {
43
+ local output="$1"
44
+ echo "$output" | grep -qE "$PROMISE_DECIDE_PATTERN"
45
+ }
46
+
47
+ # Extract the reason from a BLOCKED tag
48
+ # Usage: reason=$(extract_blocked_reason "$output")
49
+ # Returns: the reason string, or empty if no tag found
50
+ extract_blocked_reason() {
51
+ local output="$1"
52
+ local match=$(echo "$output" | grep -oE "$PROMISE_BLOCKED_PATTERN" | head -1)
53
+ if [ -n "$match" ]; then
54
+ # Extract content between BLOCKED: and </promise>
55
+ echo "$match" | sed 's/<promise>BLOCKED://;s/<\/promise>//'
56
+ fi
57
+ }
58
+
59
+ # Extract the question from a DECIDE tag
60
+ # Usage: question=$(extract_decide_question "$output")
61
+ # Returns: the question string, or empty if no tag found
62
+ extract_decide_question() {
63
+ local output="$1"
64
+ local match=$(echo "$output" | grep -oE "$PROMISE_DECIDE_PATTERN" | head -1)
65
+ if [ -n "$match" ]; then
66
+ # Extract content between DECIDE: and </promise>
67
+ echo "$match" | sed 's/<promise>DECIDE://;s/<\/promise>//'
68
+ fi
69
+ }
70
+
71
+ # Check if output contains any help-needed tag (BLOCKED or DECIDE)
72
+ # Usage: if needs_help "$output"; then ...
73
+ needs_help() {
74
+ local output="$1"
75
+ has_blocked_tag "$output" || has_decide_tag "$output"
76
+ }