@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.
- package/.agent/PROMPT.md +58 -0
- package/.agent/STEERING.md +3 -0
- package/.agent/logs/LOG.md +13 -0
- package/.agent/prd/.gitkeep +0 -0
- package/.agent/screenshots/.gitkeep +0 -0
- package/.agent/skills/component-refactoring/SKILL.md +247 -0
- package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
- package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
- package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
- package/.agent/skills/e2e-tester/SKILL.md +595 -0
- package/.agent/skills/frontend-code-review/SKILL.md +73 -0
- package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
- package/.agent/skills/frontend-code-review/references/performance.md +36 -0
- package/.agent/skills/frontend-testing/SKILL.md +316 -0
- package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
- package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
- package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
- package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
- package/.agent/skills/frontend-testing/references/checklist.md +188 -0
- package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
- package/.agent/skills/frontend-testing/references/mocking.md +289 -0
- package/.agent/skills/frontend-testing/references/workflow.md +265 -0
- package/.agent/skills/prd-creator/JSON.md +613 -0
- package/.agent/skills/prd-creator/PRD.md +196 -0
- package/.agent/skills/prd-creator/SKILL.md +143 -0
- package/.agent/skills/skill-creator/SKILL.md +355 -0
- package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
- package/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
- package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
- package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
- package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
- package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
- package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
- package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
- package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
- package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
- package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
- package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
- package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
- package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
- package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
- package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
- package/.agent/tasks/.gitkeep +0 -0
- package/.agent/tasks.json +1 -0
- package/.claude/agents/code-reviewer.md +172 -0
- package/.claude/commands/aw.md +50 -0
- package/.claude/hooks/play-sound.js +87 -0
- package/.claude/hooks/pre-tool-use.js +40 -0
- package/.claude/settings.json +54 -0
- package/.claude/settings.local.json +13 -0
- package/.mcp.json +31 -0
- package/AGENTS.md +44 -0
- package/CLAUDE.md +1 -0
- package/README.md +236 -0
- package/bin/cli.js +156 -0
- package/bin/lib/copy.js +149 -0
- package/bin/lib/display.js +137 -0
- package/package.json +65 -0
- package/ralph.sh +333 -0
- package/scripts/lib/args.sh +44 -0
- package/scripts/lib/cleanup.sh +53 -0
- package/scripts/lib/constants.sh +25 -0
- package/scripts/lib/display.sh +196 -0
- package/scripts/lib/logging.sh +30 -0
- package/scripts/lib/notify.sh +41 -0
- package/scripts/lib/output.sh +147 -0
- package/scripts/lib/preflight.sh +57 -0
- package/scripts/lib/preview.sh +77 -0
- package/scripts/lib/promise.sh +76 -0
- package/scripts/lib/spinner.sh +85 -0
- package/scripts/lib/terminal.sh +57 -0
- 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
|
+
}
|