ralph.rb 1.2.435535439
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.
- checksums.yaml +7 -0
- data/.github/workflows/gem-push.yml +47 -0
- data/.gitignore +79 -0
- data/.rubocop.yml +6018 -0
- data/.ruby-version +1 -0
- data/AGENTS.md +113 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +656 -0
- data/bin/rubocop +8 -0
- data/bin/test +5 -0
- data/exe/ralph +8 -0
- data/lib/ralph/agents/base.rb +132 -0
- data/lib/ralph/agents/claude_code.rb +24 -0
- data/lib/ralph/agents/codex.rb +25 -0
- data/lib/ralph/agents/open_code.rb +30 -0
- data/lib/ralph/agents.rb +24 -0
- data/lib/ralph/cli.rb +222 -0
- data/lib/ralph/config.rb +40 -0
- data/lib/ralph/git/file_snapshot.rb +60 -0
- data/lib/ralph/helpers.rb +76 -0
- data/lib/ralph/iteration.rb +220 -0
- data/lib/ralph/loop.rb +196 -0
- data/lib/ralph/output/active_loop_error.rb +13 -0
- data/lib/ralph/output/banner.rb +29 -0
- data/lib/ralph/output/completion_deferred.rb +12 -0
- data/lib/ralph/output/completion_detected.rb +17 -0
- data/lib/ralph/output/config_summary.rb +31 -0
- data/lib/ralph/output/context_consumed.rb +11 -0
- data/lib/ralph/output/iteration.rb +45 -0
- data/lib/ralph/output/max_iterations_reached.rb +16 -0
- data/lib/ralph/output/no_plugin_warning.rb +14 -0
- data/lib/ralph/output/nonzero_exit_warning.rb +11 -0
- data/lib/ralph/output/plugin_error.rb +12 -0
- data/lib/ralph/output/status.rb +176 -0
- data/lib/ralph/output/struggle_warning.rb +18 -0
- data/lib/ralph/output/task_completion.rb +12 -0
- data/lib/ralph/output/tasks_file_created.rb +11 -0
- data/lib/ralph/prompt_template.rb +183 -0
- data/lib/ralph/storage/context.rb +58 -0
- data/lib/ralph/storage/history.rb +117 -0
- data/lib/ralph/storage/state.rb +178 -0
- data/lib/ralph/storage/tasks.rb +244 -0
- data/lib/ralph/threads/heartbeat.rb +44 -0
- data/lib/ralph/threads/stream_reader.rb +50 -0
- data/lib/ralph/version.rb +5 -0
- data/lib/ralph.rb +67 -0
- data/original/bin/ralph.js +13 -0
- data/original/ralph.ts +1706 -0
- data/ralph.gemspec +35 -0
- data/ralph2.gemspec +35 -0
- data/screenshot.webp +0 -0
- data/specs/README.md +46 -0
- data/specs/agents.md +172 -0
- data/specs/cli.md +223 -0
- data/specs/iteration.md +173 -0
- data/specs/output.md +104 -0
- data/specs/storage/local-data-structure.md +246 -0
- data/specs/tasks.md +295 -0
- metadata +150 -0
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.4.4
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Ralph.rb Agent Guidelines
|
|
2
|
+
|
|
3
|
+
## Specifications
|
|
4
|
+
|
|
5
|
+
**IMPORTANT:** Before implementing any feature, consult the specifications in `specs/README.md`.
|
|
6
|
+
|
|
7
|
+
- **Assume NOT implemented.** Many specs describe planned features that may not yet exist in the codebase.
|
|
8
|
+
- **Check the codebase first.** Before concluding something is or isn't implemented, search the actual code. Specs describe intent; code describes reality.
|
|
9
|
+
- **Use specs as guidance.** When implementing a feature, follow the design patterns, types, and architecture defined in the relevant spec.
|
|
10
|
+
- **Spec index:** `specs/README.md` lists all specifications organized by category (core, LLM, security, etc.).
|
|
11
|
+
|
|
12
|
+
## Testing
|
|
13
|
+
|
|
14
|
+
The `bin/` directory contains scripts for verifying code quality:
|
|
15
|
+
|
|
16
|
+
- **`bin/test`** -- runs the test suite.
|
|
17
|
+
- **`bin/rubocop`** -- runs the RuboCop linter and style checks.
|
|
18
|
+
|
|
19
|
+
Run both before submitting changes to ensure tests pass and code style is consistent.
|
|
20
|
+
|
|
21
|
+
## Ruby Style
|
|
22
|
+
|
|
23
|
+
### No early returns. No guard clauses.
|
|
24
|
+
|
|
25
|
+
Methods must not use `return` to bail out early. Guard clauses (`return unless`, `return if`) create flat-looking code that hides the actual control flow. Instead, use explicit `if`/`unless` blocks. **Indentation is what creates readability** -- it visually communicates the nesting of conditions and the scope of logic.
|
|
26
|
+
|
|
27
|
+
**Bad -- guard clauses:**
|
|
28
|
+
```ruby
|
|
29
|
+
def process(data)
|
|
30
|
+
return unless data
|
|
31
|
+
return if data.empty?
|
|
32
|
+
return unless valid?(data)
|
|
33
|
+
|
|
34
|
+
do_work(data)
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Good -- explicit conditionals:**
|
|
39
|
+
```ruby
|
|
40
|
+
def process(data)
|
|
41
|
+
if data && data.any? && valid?(data)
|
|
42
|
+
do_work(data)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Use `.then` and `.tap` for pipelines
|
|
48
|
+
|
|
49
|
+
`.then` (aliased `yield_self`) and `.tap` are preferred for expressing data flow. They make the chain of operations explicit and avoid throwaway local variables.
|
|
50
|
+
|
|
51
|
+
- **`.then`** -- transforms a value and passes the result forward.
|
|
52
|
+
- **`.tap`** -- performs a side effect and returns the original value unchanged.
|
|
53
|
+
|
|
54
|
+
**Bad -- intermediate variables and guard returns:**
|
|
55
|
+
```ruby
|
|
56
|
+
def maybe_print_tool_summary(force: false)
|
|
57
|
+
return unless @compact_tools
|
|
58
|
+
return if @stream_tool_counts.empty?
|
|
59
|
+
|
|
60
|
+
now = now_ms
|
|
61
|
+
return if !force && (now - @last_tool_summary_at < @tool_summary_interval_ms)
|
|
62
|
+
|
|
63
|
+
summary = format_tool_summary(@stream_tool_counts)
|
|
64
|
+
return if summary.empty?
|
|
65
|
+
|
|
66
|
+
puts "| Tools #{summary}"
|
|
67
|
+
@last_printed_at = now_ms
|
|
68
|
+
@last_tool_summary_at = now_ms
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Good -- conditionals with `.then`:**
|
|
73
|
+
```ruby
|
|
74
|
+
def maybe_print_tool_summary(force: false)
|
|
75
|
+
if @compact_tools && @stream_tool_counts.any?
|
|
76
|
+
now = now_ms
|
|
77
|
+
if force || (now - @last_tool_summary_at >= @tool_summary_interval_ms)
|
|
78
|
+
format_tool_summary(@stream_tool_counts).then do |summary|
|
|
79
|
+
unless summary.empty?
|
|
80
|
+
puts "| Tools #{summary}"
|
|
81
|
+
@last_printed_at = now_ms
|
|
82
|
+
@last_tool_summary_at = now_ms
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### No abbreviated variable names
|
|
91
|
+
|
|
92
|
+
Variable names must never be shortened or abbreviated. Always use the full, descriptive name. Abbreviated names save a few keystrokes but cost readability every single time someone reads the code.
|
|
93
|
+
|
|
94
|
+
**Bad -- abbreviated names:**
|
|
95
|
+
```ruby
|
|
96
|
+
si = @struggle_indicators
|
|
97
|
+
cfg = load_config
|
|
98
|
+
msg = build_message(u)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Good -- full names:**
|
|
102
|
+
```ruby
|
|
103
|
+
struggle_indicators = @struggle_indicators
|
|
104
|
+
config = load_config
|
|
105
|
+
message = build_message(user)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Why this matters
|
|
109
|
+
|
|
110
|
+
- **Indentation reveals structure.** You can scan the left margin and immediately understand the conditional depth. Guard clauses flatten everything to the same level, making it impossible to see which conditions gate which logic.
|
|
111
|
+
- **Methods have one exit point.** The method body is a single expression tree. No surprises, no hidden bail-outs mid-function.
|
|
112
|
+
- **`.then` makes data flow explicit.** Instead of `x = compute(); use(x)`, you write `compute.then { |x| use(x) }`. The pipeline reads top-to-bottom, cause-to-effect.
|
|
113
|
+
- **`.tap` isolates side effects.** When you need logging, mutation, or assignment as a side effect without changing the return value, `.tap` makes that intent crystal clear.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Th0rgal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|