claude_code 0.0.16 → 0.0.18
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 +4 -4
- data/.claude/settings.local.json +5 -1
- data/.rspec_status +93 -93
- data/CHANGELOG.md +6 -0
- data/USAGE_EXAMPLES.md +35 -35
- data/claude_code-0.0.16.gem +0 -0
- data/docs/README.md +27 -27
- data/docs/mcp_integration.md +64 -64
- data/docs/streaming.md +53 -53
- data/examples/irb_helpers.rb +21 -28
- data/lib/claude_code/client.rb +120 -90
- data/lib/claude_code/version.rb +1 -1
- data/lib/claude_code.rb +5 -0
- metadata +2 -1
data/examples/irb_helpers.rb
CHANGED
@@ -7,6 +7,7 @@ require_relative '../lib/claude_code'
|
|
7
7
|
def ninja_test(prompt)
|
8
8
|
ClaudeCode.quick_mcp_query(
|
9
9
|
prompt,
|
10
|
+
model: 'sonnet',
|
10
11
|
server_name: 'ninja',
|
11
12
|
server_url: 'https://mcp-creator-ninja-v1-4-0.mcp.soy/',
|
12
13
|
tools: 'about'
|
@@ -43,18 +44,16 @@ def quick_claude(prompt, model: nil)
|
|
43
44
|
model: model,
|
44
45
|
max_turns: 1
|
45
46
|
)
|
46
|
-
|
47
|
+
|
47
48
|
ClaudeCode.query(
|
48
49
|
prompt: prompt,
|
49
50
|
options: options,
|
50
|
-
cli_path:
|
51
|
+
cli_path: '/Users/admin/.claude/local/claude'
|
51
52
|
).each do |msg|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
53
|
+
next unless msg.is_a?(ClaudeCode::AssistantMessage)
|
54
|
+
|
55
|
+
msg.content.each do |block|
|
56
|
+
puts block.text if block.is_a?(ClaudeCode::TextBlock)
|
58
57
|
end
|
59
58
|
end
|
60
59
|
end
|
@@ -65,15 +64,13 @@ def stream_claude(prompt, model: nil)
|
|
65
64
|
ClaudeCode.stream_query(
|
66
65
|
prompt: prompt,
|
67
66
|
options: ClaudeCode::ClaudeCodeOptions.new(model: model, max_turns: 1),
|
68
|
-
cli_path:
|
67
|
+
cli_path: '/Users/admin/.claude/local/claude'
|
69
68
|
) do |msg, index|
|
70
69
|
timestamp = Time.now - start_time
|
71
70
|
case msg
|
72
71
|
when ClaudeCode::AssistantMessage
|
73
72
|
msg.content.each do |block|
|
74
|
-
if block.is_a?(ClaudeCode::TextBlock)
|
75
|
-
puts "[#{format('%.2f', timestamp)}s] #{block.text}"
|
76
|
-
end
|
73
|
+
puts "[#{format('%.2f', timestamp)}s] #{block.text}" if block.is_a?(ClaudeCode::TextBlock)
|
77
74
|
end
|
78
75
|
when ClaudeCode::ResultMessage
|
79
76
|
puts "[#{format('%.2f', timestamp)}s] 💰 $#{format('%.6f', msg.total_cost_usd || 0)}"
|
@@ -86,21 +83,19 @@ def auto_stream(prompt, model: nil)
|
|
86
83
|
ClaudeCode.stream_query(
|
87
84
|
prompt: prompt,
|
88
85
|
options: ClaudeCode::ClaudeCodeOptions.new(model: model, max_turns: 1),
|
89
|
-
cli_path:
|
86
|
+
cli_path: '/Users/admin/.claude/local/claude'
|
90
87
|
)
|
91
88
|
end
|
92
89
|
|
93
90
|
# Continue the most recent conversation
|
94
91
|
def continue_chat(prompt = nil)
|
95
92
|
last_session_id = nil
|
96
|
-
|
93
|
+
|
97
94
|
ClaudeCode.continue_conversation(prompt) do |msg|
|
98
95
|
case msg
|
99
96
|
when ClaudeCode::AssistantMessage
|
100
97
|
msg.content.each do |block|
|
101
|
-
if block.is_a?(ClaudeCode::TextBlock)
|
102
|
-
puts "💬 #{block.text}"
|
103
|
-
end
|
98
|
+
puts "💬 #{block.text}" if block.is_a?(ClaudeCode::TextBlock)
|
104
99
|
end
|
105
100
|
when ClaudeCode::ResultMessage
|
106
101
|
last_session_id = msg.session_id
|
@@ -108,7 +103,7 @@ def continue_chat(prompt = nil)
|
|
108
103
|
puts "💰 $#{format('%.6f', msg.total_cost_usd || 0)}"
|
109
104
|
end
|
110
105
|
end
|
111
|
-
|
106
|
+
|
112
107
|
last_session_id
|
113
108
|
end
|
114
109
|
|
@@ -118,9 +113,7 @@ def resume_chat(session_id, prompt = nil)
|
|
118
113
|
case msg
|
119
114
|
when ClaudeCode::AssistantMessage
|
120
115
|
msg.content.each do |block|
|
121
|
-
if block.is_a?(ClaudeCode::TextBlock)
|
122
|
-
puts "💬 #{block.text}"
|
123
|
-
end
|
116
|
+
puts "💬 #{block.text}" if block.is_a?(ClaudeCode::TextBlock)
|
124
117
|
end
|
125
118
|
when ClaudeCode::ResultMessage
|
126
119
|
puts "📋 Session: #{msg.session_id}"
|
@@ -141,28 +134,28 @@ def resume_last(prompt = nil)
|
|
141
134
|
if $last_session_id
|
142
135
|
resume_chat($last_session_id, prompt)
|
143
136
|
else
|
144
|
-
puts
|
137
|
+
puts '❌ No saved session ID. Use save_session(id) first.'
|
145
138
|
end
|
146
139
|
end
|
147
140
|
|
148
|
-
puts
|
141
|
+
puts '🚀 Ruby Claude Code SDK with MCP, Streaming, and Conversation helpers loaded!'
|
149
142
|
puts
|
150
|
-
puts
|
143
|
+
puts 'Basic commands:'
|
151
144
|
puts " quick_claude('What is Ruby?')"
|
152
145
|
puts " ninja_test('Tell me about yourself')"
|
153
146
|
puts
|
154
|
-
puts
|
147
|
+
puts 'Streaming commands:'
|
155
148
|
puts " stream_claude('Explain Ruby blocks')"
|
156
149
|
puts " auto_stream('Count to 5')"
|
157
150
|
puts
|
158
|
-
puts
|
151
|
+
puts 'Conversation commands:'
|
159
152
|
puts " continue_chat('Follow up question')"
|
160
153
|
puts " resume_chat('session-id', 'New prompt')"
|
161
154
|
puts " save_session('session-id')"
|
162
155
|
puts " resume_last('New prompt')"
|
163
156
|
puts
|
164
|
-
puts
|
157
|
+
puts 'Advanced:'
|
165
158
|
puts " quick_claude('Explain arrays', model: 'sonnet')"
|
166
159
|
puts " test_mcp('prompt', 'server_name', 'server_url', 'tool_name')"
|
167
160
|
puts
|
168
|
-
puts
|
161
|
+
puts '💡 Remember to set ANTHROPIC_API_KEY environment variable!'
|
data/lib/claude_code/client.rb
CHANGED
@@ -10,42 +10,38 @@ module ClaudeCode
|
|
10
10
|
# Client setup
|
11
11
|
end
|
12
12
|
|
13
|
-
def process_query(prompt: nil, messages: nil,
|
13
|
+
def process_query(options:, prompt: nil, messages: nil, cli_path: nil, mcp_servers: {})
|
14
14
|
if messages
|
15
15
|
# Handle streaming JSON input
|
16
|
-
transport = SubprocessCLITransport.new(prompt:
|
16
|
+
transport = SubprocessCLITransport.new(prompt: '', options: options, cli_path: cli_path)
|
17
17
|
transport.connect
|
18
|
-
|
18
|
+
|
19
19
|
# Send messages
|
20
20
|
transport.send_messages(messages)
|
21
|
-
|
21
|
+
|
22
22
|
# Return enumerator for responses
|
23
23
|
return Enumerator.new do |yielder|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
yielder << message if message
|
28
|
-
end
|
29
|
-
ensure
|
30
|
-
transport.disconnect
|
24
|
+
transport.receive_messages do |data|
|
25
|
+
message = parse_message(data)
|
26
|
+
yielder << message if message
|
31
27
|
end
|
28
|
+
ensure
|
29
|
+
transport.disconnect
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
32
|
+
|
35
33
|
transport = SubprocessCLITransport.new(prompt: prompt, options: options, cli_path: cli_path)
|
36
|
-
|
34
|
+
|
37
35
|
transport.connect
|
38
|
-
|
36
|
+
|
39
37
|
# Return lazy enumerator that streams messages as they arrive
|
40
38
|
Enumerator.new do |yielder|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
yielder << message if message
|
45
|
-
end
|
46
|
-
ensure
|
47
|
-
transport.disconnect
|
39
|
+
transport.receive_messages do |data|
|
40
|
+
message = parse_message(data)
|
41
|
+
yielder << message if message
|
48
42
|
end
|
43
|
+
ensure
|
44
|
+
transport.disconnect
|
49
45
|
end
|
50
46
|
end
|
51
47
|
|
@@ -110,7 +106,7 @@ module ClaudeCode
|
|
110
106
|
end
|
111
107
|
|
112
108
|
class SubprocessCLITransport
|
113
|
-
MAX_BUFFER_SIZE = 1024 * 1024 #
|
109
|
+
MAX_BUFFER_SIZE = 1024 * 1024 * 50 # 50MB
|
114
110
|
|
115
111
|
def initialize(prompt:, options:, cli_path: nil)
|
116
112
|
@prompt = prompt
|
@@ -127,9 +123,10 @@ module ClaudeCode
|
|
127
123
|
# Use provided CLI path if valid
|
128
124
|
if cli_path
|
129
125
|
return cli_path if File.executable?(cli_path)
|
126
|
+
|
130
127
|
raise CLINotFoundError.new("CLI not found at specified path: #{cli_path}", cli_path: cli_path)
|
131
128
|
end
|
132
|
-
|
129
|
+
|
133
130
|
# Try PATH first using cross-platform which
|
134
131
|
cli = which('claude')
|
135
132
|
return cli if cli
|
@@ -198,25 +195,19 @@ module ClaudeCode
|
|
198
195
|
def build_environment
|
199
196
|
# Start with current environment
|
200
197
|
env = ENV.to_h
|
201
|
-
|
198
|
+
|
202
199
|
# Set SDK entrypoint identifier
|
203
200
|
env['CLAUDE_CODE_ENTRYPOINT'] = 'sdk-ruby'
|
204
|
-
|
201
|
+
|
205
202
|
# Ensure ANTHROPIC_API_KEY is available if set
|
206
203
|
# This allows the CLI to authenticate with Anthropic's API
|
207
|
-
if ENV['ANTHROPIC_API_KEY']
|
208
|
-
|
209
|
-
end
|
210
|
-
|
204
|
+
env['ANTHROPIC_API_KEY'] = ENV['ANTHROPIC_API_KEY'] if ENV['ANTHROPIC_API_KEY']
|
205
|
+
|
211
206
|
# Support for other authentication methods
|
212
|
-
if ENV['CLAUDE_CODE_USE_BEDROCK']
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
if ENV['CLAUDE_CODE_USE_VERTEX']
|
217
|
-
env['CLAUDE_CODE_USE_VERTEX'] = ENV['CLAUDE_CODE_USE_VERTEX']
|
218
|
-
end
|
219
|
-
|
207
|
+
env['CLAUDE_CODE_USE_BEDROCK'] = ENV['CLAUDE_CODE_USE_BEDROCK'] if ENV['CLAUDE_CODE_USE_BEDROCK']
|
208
|
+
|
209
|
+
env['CLAUDE_CODE_USE_VERTEX'] = ENV['CLAUDE_CODE_USE_VERTEX'] if ENV['CLAUDE_CODE_USE_VERTEX']
|
210
|
+
|
220
211
|
env
|
221
212
|
end
|
222
213
|
|
@@ -234,26 +225,24 @@ module ClaudeCode
|
|
234
225
|
cmd.concat(['--max-turns', @options.max_turns.to_s]) if @options.max_turns
|
235
226
|
cmd.concat(['--disallowedTools', @options.disallowed_tools.join(',')]) unless @options.disallowed_tools.empty?
|
236
227
|
cmd.concat(['--model', @options.model]) if @options.model
|
237
|
-
|
228
|
+
if @options.permission_prompt_tool_name
|
229
|
+
cmd.concat(['--permission-prompt-tool',
|
230
|
+
@options.permission_prompt_tool_name])
|
231
|
+
end
|
238
232
|
cmd.concat(['--permission-mode', @options.permission_mode]) if @options.permission_mode
|
239
233
|
cmd << '--continue' if @options.continue_conversation
|
240
234
|
cmd.concat(['--resume', @options.resume]) if @options.resume
|
241
235
|
|
242
236
|
unless @options.mcp_servers.empty?
|
243
|
-
mcp_config = { 'mcpServers' => @options.mcp_servers.transform_values
|
244
|
-
config.respond_to?(:to_h) ? config.to_h : config
|
245
|
-
|
237
|
+
mcp_config = { 'mcpServers' => @options.mcp_servers.transform_values do |config|
|
238
|
+
config.respond_to?(:to_h) ? config.to_h : config
|
239
|
+
end }
|
246
240
|
cmd.concat(['--mcp-config', JSON.generate(mcp_config)])
|
247
241
|
end
|
248
242
|
|
249
|
-
#
|
250
|
-
|
251
|
-
|
252
|
-
cmd << '--print'
|
253
|
-
else
|
254
|
-
cmd.concat(['--print', @prompt])
|
255
|
-
end
|
256
|
-
|
243
|
+
# Always use --print flag (prompt will be sent via stdin)
|
244
|
+
cmd << '--print'
|
245
|
+
|
257
246
|
cmd
|
258
247
|
end
|
259
248
|
|
@@ -262,36 +251,39 @@ module ClaudeCode
|
|
262
251
|
|
263
252
|
# Find CLI if not already set
|
264
253
|
@cli_path ||= find_cli
|
265
|
-
|
254
|
+
|
266
255
|
cmd = build_command
|
267
256
|
puts "Debug: Connecting with command: #{cmd.join(' ')}" if ENV['DEBUG_CLAUDE_SDK']
|
268
|
-
|
257
|
+
|
269
258
|
begin
|
270
259
|
env = build_environment
|
271
|
-
|
260
|
+
|
272
261
|
if @cwd
|
273
262
|
@stdin, @stdout, @stderr, @process = Open3.popen3(env, *cmd, chdir: @cwd)
|
274
263
|
else
|
275
264
|
@stdin, @stdout, @stderr, @process = Open3.popen3(env, *cmd)
|
276
265
|
end
|
277
|
-
|
266
|
+
|
278
267
|
# Handle different input modes
|
279
268
|
if @options.input_format == 'stream-json'
|
280
269
|
# Keep stdin open for streaming JSON input
|
281
|
-
puts
|
270
|
+
puts 'Debug: Keeping stdin open for streaming JSON input' if ENV['DEBUG_CLAUDE_SDK']
|
282
271
|
else
|
283
|
-
#
|
272
|
+
# Write prompt to stdin and close
|
273
|
+
if @prompt && !@prompt.empty?
|
274
|
+
puts "Debug: Writing prompt to stdin (#{@prompt.length} chars)" if ENV['DEBUG_CLAUDE_SDK']
|
275
|
+
@stdin.write(@prompt)
|
276
|
+
@stdin.flush
|
277
|
+
end
|
284
278
|
@stdin.close
|
285
279
|
end
|
286
|
-
|
280
|
+
|
287
281
|
puts "Debug: Process started with PID #{@process.pid}" if ENV['DEBUG_CLAUDE_SDK']
|
288
|
-
|
289
282
|
rescue Errno::ENOENT => e
|
290
|
-
if @cwd && !Dir.exist?(@cwd)
|
291
|
-
|
292
|
-
end
|
283
|
+
raise CLIConnectionError.new("Working directory does not exist: #{@cwd}") if @cwd && !Dir.exist?(@cwd)
|
284
|
+
|
293
285
|
raise CLINotFoundError.new("Claude Code not found at: #{@cli_path}")
|
294
|
-
rescue => e
|
286
|
+
rescue StandardError => e
|
295
287
|
raise CLIConnectionError.new("Failed to start Claude Code: #{e.class} - #{e.message}")
|
296
288
|
end
|
297
289
|
end
|
@@ -303,7 +295,7 @@ module ClaudeCode
|
|
303
295
|
# Try to terminate gracefully
|
304
296
|
if @process.alive?
|
305
297
|
Process.kill('INT', @process.pid)
|
306
|
-
|
298
|
+
|
307
299
|
# Wait for process to exit with timeout
|
308
300
|
begin
|
309
301
|
require 'timeout'
|
@@ -314,7 +306,11 @@ module ClaudeCode
|
|
314
306
|
# Force kill if it doesn't exit gracefully
|
315
307
|
begin
|
316
308
|
Process.kill('KILL', @process.pid) if @process.alive?
|
317
|
-
|
309
|
+
begin
|
310
|
+
@process.join
|
311
|
+
rescue StandardError
|
312
|
+
nil
|
313
|
+
end
|
318
314
|
rescue Errno::ESRCH
|
319
315
|
# Process already gone
|
320
316
|
end
|
@@ -323,9 +319,21 @@ module ClaudeCode
|
|
323
319
|
rescue Errno::ESRCH, Errno::ECHILD
|
324
320
|
# Process already gone
|
325
321
|
ensure
|
326
|
-
|
327
|
-
|
328
|
-
|
322
|
+
begin
|
323
|
+
@stdin&.close
|
324
|
+
rescue StandardError
|
325
|
+
nil
|
326
|
+
end
|
327
|
+
begin
|
328
|
+
@stdout&.close
|
329
|
+
rescue StandardError
|
330
|
+
nil
|
331
|
+
end
|
332
|
+
begin
|
333
|
+
@stderr&.close
|
334
|
+
rescue StandardError
|
335
|
+
nil
|
336
|
+
end
|
329
337
|
@stdin = nil
|
330
338
|
@stdout = nil
|
331
339
|
@stderr = nil
|
@@ -334,17 +342,17 @@ module ClaudeCode
|
|
334
342
|
end
|
335
343
|
|
336
344
|
def receive_messages
|
337
|
-
raise CLIConnectionError.new(
|
345
|
+
raise CLIConnectionError.new('Not connected') unless @process && @stdout
|
346
|
+
|
347
|
+
json_buffer = ''
|
338
348
|
|
339
|
-
json_buffer = ""
|
340
|
-
|
341
349
|
begin
|
342
350
|
@stdout.each_line do |line|
|
343
351
|
line = line.strip
|
344
352
|
next if line.empty?
|
345
353
|
|
346
354
|
json_lines = line.split("\n")
|
347
|
-
|
355
|
+
|
348
356
|
json_lines.each do |json_line|
|
349
357
|
json_line = json_line.strip
|
350
358
|
next if json_line.empty?
|
@@ -352,7 +360,7 @@ module ClaudeCode
|
|
352
360
|
json_buffer += json_line
|
353
361
|
|
354
362
|
if json_buffer.length > MAX_BUFFER_SIZE
|
355
|
-
json_buffer =
|
363
|
+
json_buffer = ''
|
356
364
|
raise CLIJSONDecodeError.new(
|
357
365
|
"JSON message exceeded maximum buffer size of #{MAX_BUFFER_SIZE} bytes",
|
358
366
|
StandardError.new("Buffer size #{json_buffer.length} exceeds limit #{MAX_BUFFER_SIZE}")
|
@@ -361,13 +369,12 @@ module ClaudeCode
|
|
361
369
|
|
362
370
|
begin
|
363
371
|
data = JSON.parse(json_buffer)
|
364
|
-
json_buffer =
|
372
|
+
json_buffer = ''
|
365
373
|
yield data
|
366
374
|
rescue JSON::ParserError => e
|
367
375
|
# For single-line JSON, if parsing fails, it's an error
|
368
|
-
if json_buffer.include?("\n") || json_buffer.length >
|
369
|
-
|
370
|
-
end
|
376
|
+
raise CLIJSONDecodeError.new(json_buffer, e) if json_buffer.include?("\n") || json_buffer.length > 10_000
|
377
|
+
|
371
378
|
# Otherwise continue accumulating
|
372
379
|
next
|
373
380
|
end
|
@@ -384,21 +391,44 @@ module ClaudeCode
|
|
384
391
|
data = JSON.parse(json_buffer)
|
385
392
|
yield data
|
386
393
|
rescue JSON::ParserError => e
|
387
|
-
raise CLIJSONDecodeError.new(json_buffer, StandardError.new(
|
394
|
+
raise CLIJSONDecodeError.new(json_buffer, StandardError.new('Incomplete JSON at end of stream'))
|
388
395
|
end
|
389
396
|
end
|
390
397
|
|
391
398
|
# Check for errors
|
392
399
|
exit_code = @process.value.exitstatus if @process
|
393
400
|
stderr_output = @stderr.read if @stderr
|
401
|
+
|
402
|
+
return unless exit_code && exit_code != 0
|
403
|
+
|
404
|
+
# Build helpful error message
|
405
|
+
error_message = "Command failed with exit code #{exit_code}"
|
394
406
|
|
395
|
-
if
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
407
|
+
if stderr_output.nil? || stderr_output.strip.empty?
|
408
|
+
error_message += "\n\nNo error output from Claude CLI. Common causes:"
|
409
|
+
error_message += "\n- Invalid or missing ANTHROPIC_API_KEY"
|
410
|
+
error_message += "\n- MCP server connection failed"
|
411
|
+
error_message += "\n- Network connectivity issues"
|
412
|
+
error_message += "\n- Invalid model name or options"
|
413
|
+
|
414
|
+
# Include debug info if available
|
415
|
+
if ENV['DEBUG_CLAUDE_SDK']
|
416
|
+
error_message += "\n\nDebug info:"
|
417
|
+
error_message += "\n- CLI path: #{@cli_path}"
|
418
|
+
error_message += "\n- Working directory: #{@cwd || 'current'}"
|
419
|
+
error_message += "\n- JSON buffer (last #{[json_buffer.length, 200].min} chars): #{json_buffer[-200..-1]}" if json_buffer && !json_buffer.empty?
|
420
|
+
end
|
421
|
+
|
422
|
+
error_message += "\n\nTry enabling debug mode with ENV['DEBUG_CLAUDE_SDK'] = '1' for more details"
|
423
|
+
else
|
424
|
+
error_message += "\nError output: #{stderr_output}"
|
401
425
|
end
|
426
|
+
|
427
|
+
raise ProcessError.new(
|
428
|
+
error_message,
|
429
|
+
exit_code: exit_code,
|
430
|
+
stderr: stderr_output
|
431
|
+
)
|
402
432
|
end
|
403
433
|
|
404
434
|
def connected?
|
@@ -407,31 +437,31 @@ module ClaudeCode
|
|
407
437
|
|
408
438
|
# Send a JSON message via stdin for streaming input mode
|
409
439
|
def send_message(message)
|
410
|
-
raise CLIConnectionError.new(
|
411
|
-
|
440
|
+
raise CLIConnectionError.new('Not connected to CLI') unless @stdin
|
441
|
+
|
412
442
|
json_line = message.to_json + "\n"
|
413
443
|
puts "Debug: Sending JSON message: #{json_line.strip}" if ENV['DEBUG_CLAUDE_SDK']
|
414
|
-
|
444
|
+
|
415
445
|
begin
|
416
446
|
@stdin.write(json_line)
|
417
447
|
@stdin.flush
|
418
448
|
rescue Errno::EPIPE
|
419
449
|
# Pipe is broken, process has terminated
|
420
|
-
raise CLIConnectionError.new(
|
450
|
+
raise CLIConnectionError.new('CLI process terminated unexpectedly')
|
421
451
|
end
|
422
452
|
end
|
423
453
|
|
424
454
|
# Send multiple messages and close stdin to signal end of input
|
425
455
|
def send_messages(messages)
|
426
|
-
raise CLIConnectionError.new(
|
427
|
-
|
456
|
+
raise CLIConnectionError.new('Not connected to CLI') unless @stdin
|
457
|
+
|
428
458
|
messages.each do |message|
|
429
459
|
send_message(message)
|
430
460
|
end
|
431
|
-
|
461
|
+
|
432
462
|
# Close stdin to signal end of input stream
|
433
463
|
@stdin.close
|
434
464
|
@stdin = nil
|
435
465
|
end
|
436
466
|
end
|
437
|
-
end
|
467
|
+
end
|
data/lib/claude_code/version.rb
CHANGED
data/lib/claude_code.rb
CHANGED
@@ -10,6 +10,11 @@ require_relative 'claude_code/errors'
|
|
10
10
|
require_relative 'claude_code/client'
|
11
11
|
|
12
12
|
module ClaudeCode
|
13
|
+
# Check if API key is configured
|
14
|
+
def self.api_key_configured?
|
15
|
+
!ENV['ANTHROPIC_API_KEY'].nil? && !ENV['ANTHROPIC_API_KEY'].strip.empty?
|
16
|
+
end
|
17
|
+
|
13
18
|
# Main query method - supports both positional and keyword arguments
|
14
19
|
def self.query(prompt_or_args = nil, prompt: nil, options: nil, cli_path: nil, mcp_servers: {}, &block)
|
15
20
|
# Handle positional argument for backward compatibility
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: claude_code
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Your Name
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- README.md
|
169
169
|
- Rakefile
|
170
170
|
- USAGE_EXAMPLES.md
|
171
|
+
- claude_code-0.0.16.gem
|
171
172
|
- claude_code.gemspec
|
172
173
|
- docs/README.md
|
173
174
|
- docs/mcp_integration.md
|