openclacky 0.5.4 → 0.5.6

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.
@@ -22,6 +22,11 @@ module Clacky
22
22
  hard_timeout: {
23
23
  type: "integer",
24
24
  description: "Hard timeout in seconds (force kill)"
25
+ },
26
+ max_output_lines: {
27
+ type: "integer",
28
+ description: "Maximum number of output lines to return (default: 1000)",
29
+ default: 1000
25
30
  }
26
31
  },
27
32
  required: ["command"]
@@ -51,7 +56,7 @@ module Clacky
51
56
  'go build'
52
57
  ].freeze
53
58
 
54
- def execute(command:, soft_timeout: nil, hard_timeout: nil)
59
+ def execute(command:, soft_timeout: nil, hard_timeout: nil, max_output_lines: 1000)
55
60
  require "open3"
56
61
  require "stringio"
57
62
 
@@ -82,7 +87,8 @@ module Clacky
82
87
  stderr_buffer.string,
83
88
  elapsed,
84
89
  :hard_timeout,
85
- hard_timeout
90
+ hard_timeout,
91
+ max_output_lines
86
92
  )
87
93
  end
88
94
 
@@ -97,7 +103,8 @@ module Clacky
97
103
  command,
98
104
  stdout_buffer.string,
99
105
  stderr_buffer.string,
100
- interaction
106
+ interaction,
107
+ max_output_lines
101
108
  )
102
109
  end
103
110
 
@@ -114,7 +121,8 @@ module Clacky
114
121
  command,
115
122
  stdout_buffer.string,
116
123
  stderr_buffer.string,
117
- elapsed
124
+ elapsed,
125
+ max_output_lines
118
126
  )
119
127
  end
120
128
  end
@@ -151,22 +159,30 @@ module Clacky
151
159
  rescue StandardError
152
160
  end
153
161
 
162
+ stdout_output = stdout_buffer.string
163
+ stderr_output = stderr_buffer.string
164
+
154
165
  {
155
166
  command: command,
156
- stdout: stdout_buffer.string,
157
- stderr: stderr_buffer.string,
167
+ stdout: truncate_output(stdout_output, max_output_lines),
168
+ stderr: truncate_output(stderr_output, max_output_lines),
158
169
  exit_code: wait_thr.value.exitstatus,
159
170
  success: wait_thr.value.success?,
160
- elapsed: Time.now - start_time
171
+ elapsed: Time.now - start_time,
172
+ output_truncated: output_truncated?(stdout_output, stderr_output, max_output_lines)
161
173
  }
162
174
  end
163
175
  rescue StandardError => e
176
+ stdout_output = stdout_buffer.string
177
+ stderr_output = "Error executing command: #{e.message}\n#{e.backtrace.first(3).join("\n")}"
178
+
164
179
  {
165
180
  command: command,
166
- stdout: stdout_buffer.string,
167
- stderr: "Error executing command: #{e.message}\n#{e.backtrace.first(3).join("\n")}",
181
+ stdout: truncate_output(stdout_output, max_output_lines),
182
+ stderr: truncate_output(stderr_output, max_output_lines),
168
183
  exit_code: -1,
169
- success: false
184
+ success: false,
185
+ output_truncated: output_truncated?(stdout_output, stderr_output, max_output_lines)
170
186
  }
171
187
  end
172
188
  end
@@ -206,16 +222,17 @@ module Clacky
206
222
  nil
207
223
  end
208
224
 
209
- def format_waiting_input_result(command, stdout, stderr, interaction)
225
+ def format_waiting_input_result(command, stdout, stderr, interaction, max_output_lines)
210
226
  {
211
227
  command: command,
212
- stdout: stdout,
213
- stderr: stderr,
228
+ stdout: truncate_output(stdout, max_output_lines),
229
+ stderr: truncate_output(stderr, max_output_lines),
214
230
  exit_code: -2,
215
231
  success: false,
216
232
  state: 'WAITING_INPUT',
217
233
  interaction_type: interaction[:type],
218
- message: format_waiting_message(stdout, interaction)
234
+ message: format_waiting_message(truncate_output(stdout, max_output_lines), interaction),
235
+ output_truncated: output_truncated?(stdout, stderr, max_output_lines)
219
236
  }
220
237
  end
221
238
 
@@ -238,16 +255,17 @@ module Clacky
238
255
  MSG
239
256
  end
240
257
 
241
- def format_stuck_result(command, stdout, stderr, elapsed)
258
+ def format_stuck_result(command, stdout, stderr, elapsed, max_output_lines)
242
259
  {
243
260
  command: command,
244
- stdout: stdout,
245
- stderr: stderr,
261
+ stdout: truncate_output(stdout, max_output_lines),
262
+ stderr: truncate_output(stderr, max_output_lines),
246
263
  exit_code: -3,
247
264
  success: false,
248
265
  state: 'STUCK',
249
266
  elapsed: elapsed,
250
- message: format_stuck_message(stdout, elapsed)
267
+ message: format_stuck_message(truncate_output(stdout, max_output_lines), elapsed),
268
+ output_truncated: output_truncated?(stdout, stderr, max_output_lines)
251
269
  }
252
270
  end
253
271
 
@@ -267,18 +285,38 @@ module Clacky
267
285
  MSG
268
286
  end
269
287
 
270
- def format_timeout_result(command, stdout, stderr, elapsed, type, timeout)
288
+ def format_timeout_result(command, stdout, stderr, elapsed, type, timeout, max_output_lines)
271
289
  {
272
290
  command: command,
273
- stdout: stdout,
274
- stderr: stderr.empty? ? "Command timed out after #{elapsed.round(1)} seconds (#{type}=#{timeout}s)" : stderr,
291
+ stdout: truncate_output(stdout, max_output_lines),
292
+ stderr: truncate_output(stderr.empty? ? "Command timed out after #{elapsed.round(1)} seconds (#{type}=#{timeout}s)" : stderr, max_output_lines),
275
293
  exit_code: -1,
276
294
  success: false,
277
295
  state: 'TIMEOUT',
278
- timeout_type: type
296
+ timeout_type: type,
297
+ output_truncated: output_truncated?(stdout, stderr, max_output_lines)
279
298
  }
280
299
  end
281
300
 
301
+ # Truncate output to max_lines, adding a truncation notice if needed
302
+ def truncate_output(output, max_lines)
303
+ return output if output.nil? || output.empty?
304
+
305
+ lines = output.lines
306
+ return output if lines.length <= max_lines
307
+
308
+ truncated_lines = lines.first(max_lines)
309
+ truncation_notice = "\n\n... [Output truncated: showing #{max_lines} of #{lines.length} lines] ...\n"
310
+ truncated_lines.join + truncation_notice
311
+ end
312
+
313
+ # Check if output was truncated
314
+ def output_truncated?(stdout, stderr, max_lines)
315
+ stdout_lines = stdout&.lines&.length || 0
316
+ stderr_lines = stderr&.lines&.length || 0
317
+ stdout_lines > max_lines || stderr_lines > max_lines
318
+ end
319
+
282
320
  def format_call(args)
283
321
  cmd = args[:command] || args['command'] || ''
284
322
  cmd_parts = cmd.split
@@ -9,10 +9,10 @@ module Clacky
9
9
  LOGO = <<~'LOGO'
10
10
  ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗██╗ █████╗ ██████╗██╗ ██╗██╗ ██╗
11
11
  ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██║ ██╔══██╗██╔════╝██║ ██╔╝╚██╗ ██╔╝
12
- ██║ ██║██████╔╝█████╗ ██╔██╗ ██║██║ ██║ ███████║██║ █████╔╝ ╚████╔╝
13
- ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║ ██╔══██║██║ ██╔═██╗ ╚██╔╝
14
- ╚██████╔╝██║ ███████╗██║ ╚████║╚██████╗███████╗██║ ██║╚██████╗██║ ██╗ ██║
15
- ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝
12
+ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║██║ ██║ ███████║██║ █████╔╝ ╚████╔╝
13
+ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║ ██╔══██║██║ ██╔═██╗ ╚██╔╝
14
+ ╚██████╔╝██║ ███████╗██║ ╚████║╚██████╗███████╗██║ ██║╚██████╗██║ ██╗ ██║
15
+ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝
16
16
  LOGO
17
17
 
18
18
  TAGLINE = "[>] AI Coding Assistant & Technical Co-founder"
@@ -72,25 +72,36 @@ module Clacky
72
72
  end
73
73
 
74
74
  # Display task completion summary
75
- def display_task_complete(iterations:, cost:, total_tasks:, total_cost:, cache_stats: {})
75
+ def display_task_complete(iterations:, cost:, total_tasks:, total_cost:, cost_source:, cache_stats: {})
76
76
  puts
77
77
  puts separator("-")
78
78
  puts @pastel.bright_green("[✓] TASK COMPLETED")
79
79
  puts info_line("Iterations", iterations)
80
- puts info_line("Cost", "$#{cost}")
80
+
81
+ # Add cost source indicator
82
+ cost_suffix = case cost_source
83
+ when :api
84
+ " (by API)"
85
+ when :price
86
+ " (by PRICE)"
87
+ when :default
88
+ " (by DEFAULT)"
89
+ else
90
+ " (estimated)"
91
+ end
92
+ puts info_line("Cost", "$#{cost}#{cost_suffix}")
81
93
  puts info_line("Session Total", "#{total_tasks} tasks, $#{total_cost}")
82
-
94
+
83
95
  # Display cache statistics if available
84
96
  if cache_stats[:total_requests] && cache_stats[:total_requests] > 0
85
97
  puts
86
98
  puts @pastel.cyan(" [Prompt Caching]")
87
- puts info_line(" Cache Writes", "#{cache_stats[:cache_creation_input_tokens]} tokens")
88
- puts info_line(" Cache Reads", "#{cache_stats[:cache_read_input_tokens]} tokens")
89
-
99
+ puts info_line(" Cache Reads/Writes", "#{cache_stats[:cache_read_input_tokens]}/#{cache_stats[:cache_creation_input_tokens]} tokens")
100
+
90
101
  hit_rate = (cache_stats[:cache_hit_requests].to_f / cache_stats[:total_requests] * 100).round(1)
91
102
  puts info_line(" Cache Hit Rate", "#{hit_rate}% (#{cache_stats[:cache_hit_requests]}/#{cache_stats[:total_requests]} requests)")
92
103
  end
93
-
104
+
94
105
  puts separator("-")
95
106
  puts
96
107
  end