Skip to content

Commit 7754d2e

Browse files
committed
Replace wiggum with ralph
1 parent e126009 commit 7754d2e

2 files changed

Lines changed: 215 additions & 160 deletions

File tree

lib/scripts/ralph

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'date'
4+
require 'json'
5+
require 'optparse'
6+
require 'open3'
7+
8+
def parsed_loop_options
9+
options = {
10+
"model" => "opus",
11+
"completion_promise" => "ALLDONE",
12+
"max_iterations" => 100,
13+
}
14+
15+
OptionParser.new do |opts|
16+
opts.on('--prompt PROMPT', 'prompt') { |it| options["prompt"] = it }
17+
opts.on('--completion-promise COMPLETION_PROMISE', 'completion promise') { |it| options["completion_promise"] = it }
18+
opts.on('--max-iterations MAX_ITERATIONS', 'maximum iterations') { |it| options["max_iterations"] = it.to_i }
19+
opts.on('--model MODEL', 'model to use') { |it| options["model"] = it }
20+
end.parse!
21+
22+
options
23+
end
24+
25+
def parsed_next_options
26+
options = {
27+
"file" => 'ralph-tasks.json',
28+
"open_status" => 'open',
29+
}
30+
31+
OptionParser.new do |opts|
32+
opts.on('--file FILE', 'task file') { options["file"] = it }
33+
opts.on('--open-status STATUS', 'status indicating open task') { options["open_status"] = it }
34+
end.parse!
35+
36+
options
37+
end
38+
39+
def parsed_update_options
40+
options = {
41+
"file" => 'ralph-tasks.json',
42+
}
43+
44+
OptionParser.new do |opts|
45+
opts.on('--file FILE', 'task file') { options["file"] = it }
46+
opts.on('--id ID', 'task identifier') { options["id"] = it }
47+
opts.on('--status STATUS', 'updated status') { options["status"] = it }
48+
opts.on('--comment "COMMENTS IN QUOTES"', 'comment on result') { options["comments"] = it }
49+
opts.on('--pull-request PULL_REQUEST', 'optional PR URL') { options["pull_request"] = it }
50+
end.parse!
51+
52+
options
53+
end
54+
55+
class Loop
56+
def initialize(prompt:, completion_promise:, max_iterations:, model:)
57+
@prompt_file = prompt
58+
@completion_promise = completion_promise
59+
@max_iterations = max_iterations
60+
@model = model
61+
@iteration = 0
62+
end
63+
64+
attr_reader :completion_promise, :max_iterations, :iteration, :model, :prompt_file
65+
66+
def run!
67+
puts <<~START
68+
69+
=== Ralph: starting run ===
70+
prompt: #{prompt_file}
71+
model: #{model}
72+
max_iterations: #{max_iterations}
73+
completion_promise: #{completion_promise}
74+
===========================
75+
76+
START
77+
78+
while iteration < max_iterations
79+
puts "=== Ralph: iteration #{iteration + 1} ==="
80+
81+
stdout, stderr, status = Open3.capture3(
82+
"claude -p --dangerously-skip-permissions --model #{model}",
83+
stdin_data: prompt
84+
)
85+
86+
if status.success?
87+
puts stdout
88+
89+
if stdout.include?(completion_promise)
90+
puts "=== Ralph: received completion promise '#{completion_promise}'. Exiting. ==="
91+
exit 0
92+
end
93+
94+
@iteration += 1
95+
else
96+
puts stderr
97+
exit 1
98+
end
99+
end
100+
101+
puts "=== Ralph: performed #{iteration} iterations. Exiting. ==="
102+
end
103+
104+
def prompt
105+
<<~PROMPT
106+
#{prompt_file}
107+
108+
## Tool reference
109+
110+
- `./ralph help` prints usage
111+
- `./ralph next-task` - returns JSON of the task to work on.
112+
- If it returns `'{ "_no_remaining_tasks": true }'`, that means no tasks remain to work on. Immediately exit
113+
- `./ralph update-task` - updates the status and data on a task. Use it to update tasks after you have attempted them.
114+
PROMPT
115+
end
116+
end
117+
118+
class NextTask
119+
def initialize(file:, open_status:)
120+
@file = file
121+
@open_status = open_status
122+
end
123+
124+
attr_reader :file, :open_status
125+
126+
def get!
127+
data = JSON.parse(File.read(file))
128+
next_task = data.find { |d| d["status"] == open_status }
129+
130+
if next_task.nil?
131+
return { "_no_remaining_tasks" => true }
132+
end
133+
134+
next_task
135+
end
136+
end
137+
138+
class UpdateTask
139+
def initialize(file:, task_id:, status:, comment:, pull_request: nil)
140+
@file = file
141+
@task_id = task_id
142+
@status = status
143+
@comment = comment
144+
@pull_request = pull_request
145+
end
146+
147+
attr_reader :file, :task_id, :status, :comment, :pull_request
148+
149+
def update!
150+
data = JSON.parse(File.read(file))
151+
task_index = data.index { |d| d["id"] == task_id }
152+
153+
comments = task["comments"] || []
154+
comments << {
155+
"time": DateTime.now.iso8601,
156+
"comment" => comment
157+
}
158+
159+
data[task_index] = datum.merge({
160+
"status" => status,
161+
"comments" => comments,
162+
"pull_request" => options.fetch("pull_request", nil)
163+
})
164+
165+
File.write(file, JSON.pretty_generate(data))
166+
end
167+
end
168+
169+
LOOP_COMMAND = "loop"
170+
NEXT_COMMAND = "next-task"
171+
UPDATE_COMMAND = "update-task"
172+
HELP_COMMAND = "help"
173+
174+
command = ARGV.shift
175+
176+
case command
177+
when LOOP_COMMAND
178+
loop_options = parsed_loop_options
179+
180+
Loop.new(
181+
prompt: loop_options.fetch("prompt"),
182+
completion_promise: loop_options.fetch("completion_promise"),
183+
max_iterations: loop_options.fetch("max_iterations"),
184+
model: loop_options.fetch("model"),
185+
).run!
186+
when NEXT_COMMAND
187+
next_options = parsed_next_options
188+
189+
puts JSON.pretty_generate(
190+
NextTask.new(
191+
file: next_options.fetch("file"),
192+
open_status: next_options.fetch("open_status"),
193+
).get!
194+
)
195+
when UPDATE_COMMAND
196+
update_options = parsed_update_options
197+
198+
UpdateTask.new(
199+
file: update_options.fetch("file"),
200+
task_id: update_options.fetch("id"),
201+
status: update_options.fetch("status"),
202+
comment: update_options.fetch("comments", nil),
203+
pull_request: update_options.fetch("pull_request", nil),
204+
).update!
205+
when HELP_COMMAND
206+
puts <<~HELP
207+
Usage: ralph loop --prompt <prompt> --completion-promise <completion_promise> --max-iterations <max_iterations> [--model <model=opus>]
208+
Usage: ralph next-task [--file <task_file=ralph-tasks.json>] [--open-status <open_status=open>]
209+
Usage: ralph update-task --id <task_id> --status <status> [--comment "comments in quotes"] [--pull-request <pull_request>] [--file <task_file=ralph-tasks.json>]
210+
HELP
211+
else
212+
raise "Unknown command: #{command}"
213+
end
214+
215+

lib/zsh/functions/wiggum

Lines changed: 0 additions & 160 deletions
This file was deleted.

0 commit comments

Comments
 (0)