ruby-claw 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a656bdeb580e8d10ca17f5e6f74a7406027da83488c4b1d256a4dd5e4e93de01
4
- data.tar.gz: 6c4474049cad5f10148c9dd9b5960e6b1b521ecaef73720a326e796861a58a92
3
+ metadata.gz: aa6ced1593ea714dd01b174b68790fbe34b07429be8494e9ea5e81cbc0c082a5
4
+ data.tar.gz: e2b1a0acf79b75834c387c380f7c1f14867e4e139708fd7e27ccf03c4a0e46cd
5
5
  SHA512:
6
- metadata.gz: 68810da4b3c804ff7bd61fa9d4662ce622ad20380dc91222c979ae6ab5b82fd311f5c56ec3e96702df4bcec8790015f4b4ac5b81aeb8f5187cc3d41c7eba3f9c
7
- data.tar.gz: 559a0c8d419cc42215a2d96d78575d3b38e14b9f4915e14859da25dbdf3f05fed591b895cf77261b8793555b8fb6faa61b7f67b56a9a5e95c5dc24a35e11a294
6
+ metadata.gz: 7417f232d861f3148e72ef3d62d127c2da504adb6948d79b984b660dafe84aa640017651867cdaf1d85a3383c9943c83c888bdf8fdaf3886b30d0587a8758134
7
+ data.tar.gz: b4a3c308724f47181c4f2cd38d57908ac95904d233c041ca320b529f65715e64dbc0ec7e9c110147e6d492d22f8cf2708d85d4e1095a452a6ef32b7fe9be7ed9
@@ -17,7 +17,7 @@ module Claw
17
17
  @runtime = init_runtime(caller_binding)
18
18
  @chat_history = []
19
19
  @mode = :normal # :normal | :plan
20
- @input_text = ""
20
+ @input_text = +""
21
21
  @input_focused = true
22
22
  @scrolled_up = false
23
23
  @text_buffer = +"" # accumulates streaming text
@@ -40,46 +40,47 @@ module Claw
40
40
 
41
41
  def init
42
42
  @chat_history << { role: :system, content: "Claw agent ready · type 'exit' to quit" }
43
- cmd = @spinner.init
44
- Bubbletea.batch(cmd, Bubbletea.tick(1.0) { TickMsg.new(time: Time.now) })
43
+ [self, Bubbletea.batch(@spinner.tick, Bubbletea.tick(1.0) { TickMsg.new(time: Time.now) })]
45
44
  end
46
45
 
47
46
  def update(msg)
48
- case msg
49
- when Bubbletea::KeyMessage
50
- handle_key(msg)
51
- when TickMsg
52
- cmd = @spinner.update(@spinner.tick)
53
- Bubbletea.batch(cmd, Bubbletea.tick(1.0) { TickMsg.new(time: Time.now) })
54
- when AgentTextMsg
55
- @text_buffer << msg.text
56
- Bubbletea.none
57
- when ToolCallMsg
58
- flush_text_buffer
59
- detail = format_tool_detail(msg.name, msg.input)
60
- @chat_history << { role: :tool_call, icon: "⚡", detail: detail }
61
- Bubbletea.none
62
- when ToolResultMsg
63
- @chat_history << { role: :tool_result, result: msg.result } unless msg.result.to_s.start_with?("ok:")
64
- Bubbletea.none
65
- when ExecutionDoneMsg
66
- flush_text_buffer
67
- write_trace(msg.trace)
68
- Claw.memory&.schedule_compaction
69
- Bubbletea.none
70
- when ExecutionErrorMsg
71
- flush_text_buffer
72
- @chat_history << { role: :error, content: msg.error.message }
73
- Bubbletea.none
74
- when CommandResultMsg
75
- handle_command_result(msg)
76
- Bubbletea.none
77
- when StateChangeMsg
78
- # Runtime state changed — triggers re-render via Bubbletea
79
- Bubbletea.none
80
- else
81
- Bubbletea.none
82
- end
47
+ cmd = case msg
48
+ when Bubbletea::KeyMessage
49
+ return handle_key(msg)
50
+ when Bubbles::Spinner::TickMessage
51
+ @spinner, spinner_cmd = @spinner.update(msg)
52
+ Bubbletea.batch(spinner_cmd, Bubbletea.tick(1.0) { TickMsg.new(time: Time.now) })
53
+ when TickMsg
54
+ Bubbletea.tick(1.0) { TickMsg.new(time: Time.now) }
55
+ when AgentTextMsg
56
+ @text_buffer << msg.text
57
+ Bubbletea.none
58
+ when ToolCallMsg
59
+ flush_text_buffer
60
+ detail = format_tool_detail(msg.name, msg.input)
61
+ @chat_history << { role: :tool_call, icon: "⚡", detail: detail }
62
+ Bubbletea.none
63
+ when ToolResultMsg
64
+ @chat_history << { role: :tool_result, result: msg.result } unless msg.result.to_s.start_with?("ok:")
65
+ Bubbletea.none
66
+ when ExecutionDoneMsg
67
+ flush_text_buffer
68
+ write_trace(msg.trace)
69
+ Claw.memory&.schedule_compaction
70
+ Bubbletea.none
71
+ when ExecutionErrorMsg
72
+ flush_text_buffer
73
+ @chat_history << { role: :error, content: msg.error.message }
74
+ Bubbletea.none
75
+ when CommandResultMsg
76
+ handle_command_result(msg)
77
+ Bubbletea.none
78
+ when StateChangeMsg
79
+ Bubbletea.none
80
+ else
81
+ Bubbletea.none
82
+ end
83
+ [self, cmd]
83
84
  end
84
85
 
85
86
  def view
@@ -111,47 +112,46 @@ module Claw
111
112
  def handle_key(msg)
112
113
  key = msg.to_s
113
114
 
114
- case key
115
- when "ctrl+c", "ctrl+d"
116
- save_state
117
- return Bubbletea.quit
118
- when "enter"
119
- return submit_input
120
- when "pgup"
121
- @chat_viewport.page_up
122
- @scrolled_up = true
123
- return Bubbletea.none
124
- when "pgdown"
125
- @chat_viewport.page_down
126
- @scrolled_up = @chat_viewport.at_bottom? ? false : true
127
- return Bubbletea.none
128
- when "backspace"
129
- @input_text = @input_text[0..-2] if @input_text.length > 0
130
- return Bubbletea.none
131
- end
132
-
133
- # Regular character input
134
- if key.length == 1 && key.ord >= 32
135
- @input_text << key
136
- end
137
- Bubbletea.none
115
+ cmd = case key
116
+ when "ctrl+c", "ctrl+d"
117
+ save_state
118
+ return [self, Bubbletea.quit]
119
+ when "enter"
120
+ return submit_input
121
+ when "pgup"
122
+ @chat_viewport.page_up
123
+ @scrolled_up = true
124
+ Bubbletea.none
125
+ when "pgdown"
126
+ @chat_viewport.page_down
127
+ @scrolled_up = @chat_viewport.at_bottom? ? false : true
128
+ Bubbletea.none
129
+ when "backspace"
130
+ @input_text = @input_text[0..-2] if @input_text.length > 0
131
+ Bubbletea.none
132
+ else
133
+ # Regular character input
134
+ @input_text << key if key.length == 1 && key.ord >= 32
135
+ Bubbletea.none
136
+ end
137
+ [self, cmd]
138
138
  end
139
139
 
140
140
  def submit_input
141
141
  text = @input_text.strip
142
- @input_text = ""
143
- return Bubbletea.none if text.empty?
142
+ @input_text = +""
143
+ return [self, Bubbletea.none] if text.empty?
144
144
 
145
145
  # Busy guard — prevent concurrent LLM executions
146
146
  if @executor.running? && !text.start_with?("/") && !text.start_with?("!") && !text.match?(/\A(exit|quit|bye|q)\z/i)
147
147
  @chat_history << { role: :system, content: "Agent is busy — please wait for the current execution to finish." }
148
- return Bubbletea.none
148
+ return [self, Bubbletea.none]
149
149
  end
150
150
 
151
151
  # Exit
152
152
  if text.match?(/\A(exit|quit|bye|q)\z/i)
153
153
  save_state
154
- return Bubbletea.quit
154
+ return [self, Bubbletea.quit]
155
155
  end
156
156
 
157
157
  @chat_history << { role: :user, content: text }
@@ -175,7 +175,7 @@ module Claw
175
175
  if cmd == "plan"
176
176
  @mode = @mode == :plan ? :normal : :plan
177
177
  @chat_history << { role: :system, content: "mode: #{@mode}" }
178
- return Bubbletea.none
178
+ return [self, Bubbletea.none]
179
179
  end
180
180
 
181
181
  # Object explorer commands
@@ -186,7 +186,7 @@ module Claw
186
186
  lines = result[:data].flat_map { |section, items| ["#{section}:", *items] }
187
187
  @chat_history << { role: :system, content: lines.join("\n") }
188
188
  end
189
- return Bubbletea.none
189
+ return [self, Bubbletea.none]
190
190
  when "cd"
191
191
  @nav_stack ||= []
192
192
  result = ObjectExplorer.cd(arg || "..", @caller_binding, @nav_stack)
@@ -196,7 +196,7 @@ module Claw
196
196
  else
197
197
  @chat_history << { role: :error, content: result[:message] }
198
198
  end
199
- return Bubbletea.none
199
+ return [self, Bubbletea.none]
200
200
  when "source"
201
201
  result = ObjectExplorer.source(arg.to_s, @caller_binding)
202
202
  if result[:type] == :data
@@ -204,11 +204,11 @@ module Claw
204
204
  else
205
205
  @chat_history << { role: :error, content: result[:message] }
206
206
  end
207
- return Bubbletea.none
207
+ return [self, Bubbletea.none]
208
208
  when "doc"
209
209
  result = ObjectExplorer.doc(arg.to_s, @caller_binding)
210
210
  @chat_history << { role: :system, content: result[:data][:doc].to_s }
211
- return Bubbletea.none
211
+ return [self, Bubbletea.none]
212
212
  when "find"
213
213
  result = ObjectExplorer.find(arg.to_s, @caller_binding)
214
214
  if result[:type] == :data
@@ -216,17 +216,17 @@ module Claw
216
216
  else
217
217
  @chat_history << { role: :system, content: result[:message] }
218
218
  end
219
- return Bubbletea.none
219
+ return [self, Bubbletea.none]
220
220
  when "whereami"
221
221
  result = ObjectExplorer.whereami(@caller_binding)
222
222
  d = result[:data]
223
223
  @chat_history << { role: :system, content: "#{d[:file]}:#{d[:line]} (#{d[:receiver]})" }
224
- return Bubbletea.none
224
+ return [self, Bubbletea.none]
225
225
  end
226
226
 
227
227
  result = Claw::Commands.dispatch(cmd, arg, runtime: @runtime)
228
228
  handle_command_result(CommandResultMsg.new(result: result, cmd: cmd))
229
- Bubbletea.none
229
+ [self, Bubbletea.none]
230
230
  end
231
231
 
232
232
  def handle_ruby(code)
@@ -241,7 +241,7 @@ module Claw
241
241
  @chat_history << { role: :error, content: "#{eval_result[:error].class}: #{eval_result[:error].message}" }
242
242
  end
243
243
  @runtime&.resources&.dig("binding")&.scan_binding
244
- Bubbletea.none
244
+ [self, Bubbletea.none]
245
245
  end
246
246
 
247
247
  def handle_ruby_or_llm(text)
@@ -249,12 +249,12 @@ module Claw
249
249
  if eval_result[:success]
250
250
  @chat_history << { role: :ruby, content: eval_result[:result].inspect }
251
251
  @runtime&.resources&.dig("binding")&.scan_binding
252
- Bubbletea.none
252
+ [self, Bubbletea.none]
253
253
  elsif eval_result[:error].is_a?(NameError) && (text.include?(" ") || text.match?(/[^\x00-\x7F]/))
254
254
  handle_llm(text)
255
255
  else
256
256
  @chat_history << { role: :error, content: "#{eval_result[:error].class}: #{eval_result[:error].message}" }
257
- Bubbletea.none
257
+ [self, Bubbletea.none]
258
258
  end
259
259
  end
260
260
 
@@ -274,7 +274,7 @@ module Claw
274
274
  @executor.execute(text, @caller_binding) do |event|
275
275
  Bubbletea.send_message(event)
276
276
  end
277
- Bubbletea.none
277
+ [self, Bubbletea.none]
278
278
  end
279
279
 
280
280
  def handle_command_result(msg)
data/lib/claw/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Claw
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-claw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Li