claude_code_sdk 0.1.0
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/.rspec +3 -0
- data/.rubocop.yml +38 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +36 -0
- data/CLAUDE.md +86 -0
- data/CONTRIBUTING.md +82 -0
- data/LICENSE +21 -0
- data/README.md +304 -0
- data/Rakefile +32 -0
- data/claude_code_sdk.gemspec +54 -0
- data/examples/debug_process.rb +60 -0
- data/examples/debug_query.rb +34 -0
- data/examples/simple_query.rb +23 -0
- data/examples/simple_test.rb +18 -0
- data/examples/simple_tools.rb +31 -0
- data/examples/simple_tools_fixed.rb +33 -0
- data/examples/streaming_responses.rb +39 -0
- data/examples/test_sdk.rb +45 -0
- data/examples/with_tools.rb +35 -0
- data/lib/claude_code_sdk/configuration.rb +27 -0
- data/lib/claude_code_sdk/errors.rb +45 -0
- data/lib/claude_code_sdk/internal/client.rb +122 -0
- data/lib/claude_code_sdk/messages.rb +101 -0
- data/lib/claude_code_sdk/transport/base.rb +24 -0
- data/lib/claude_code_sdk/transport/simple_cli.rb +108 -0
- data/lib/claude_code_sdk/transport/subprocess_cli.rb +167 -0
- data/lib/claude_code_sdk/types.rb +63 -0
- data/lib/claude_code_sdk/version.rb +5 -0
- data/lib/claude_code_sdk.rb +84 -0
- metadata +262 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
4
|
+
require "json"
|
5
|
+
require "shellwords"
|
6
|
+
|
7
|
+
module ClaudeCodeSDK
|
8
|
+
module Transport
|
9
|
+
class SimpleCLI < Base
|
10
|
+
def initialize(prompt:, options: nil)
|
11
|
+
@prompt = prompt
|
12
|
+
@options = options || Options.new
|
13
|
+
@connected = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def connect
|
17
|
+
@connected = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def disconnect
|
21
|
+
@connected = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def connected?
|
25
|
+
@connected
|
26
|
+
end
|
27
|
+
|
28
|
+
def receive_messages
|
29
|
+
cli_path = find_cli_path
|
30
|
+
raise CLINotFoundError.new(cli_path: cli_path) unless cli_path
|
31
|
+
|
32
|
+
args = @options.to_cli_args
|
33
|
+
args.push(@prompt)
|
34
|
+
|
35
|
+
command = "#{cli_path} #{args.map { |arg| Shellwords.escape(arg) }.join(" ")}"
|
36
|
+
puts "[DEBUG] Command: #{command}" if ENV["DEBUG"]
|
37
|
+
|
38
|
+
# Set environment variable
|
39
|
+
env = { "ANTHROPIC_API_KEY" => ENV.fetch("ANTHROPIC_API_KEY", nil) }
|
40
|
+
|
41
|
+
# Run command and capture output
|
42
|
+
output = IO.popen(env, command, "r", &:read)
|
43
|
+
exit_status = $CHILD_STATUS.exitstatus
|
44
|
+
|
45
|
+
puts "[DEBUG] Exit status: #{exit_status}" if ENV["DEBUG"]
|
46
|
+
puts "[DEBUG] Output: #{output}" if ENV["DEBUG"]
|
47
|
+
|
48
|
+
# Check for errors
|
49
|
+
unless $CHILD_STATUS.success?
|
50
|
+
raise ProcessError.new(
|
51
|
+
"Claude Code process failed",
|
52
|
+
exit_code: exit_status,
|
53
|
+
stderr: output
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Parse the JSON response
|
58
|
+
begin
|
59
|
+
data = JSON.parse(output, symbolize_names: true)
|
60
|
+
|
61
|
+
# The response is a single result object, but we need to yield messages
|
62
|
+
if data[:type] == "result" && data[:result]
|
63
|
+
# Yield a user message with the prompt
|
64
|
+
yield({ type: "user", text: @prompt })
|
65
|
+
|
66
|
+
# Yield an assistant message with the response
|
67
|
+
yield({
|
68
|
+
type: "assistant",
|
69
|
+
message: {
|
70
|
+
id: "msg-#{data[:session_id]}",
|
71
|
+
content: [{ type: "text", text: data[:result] }]
|
72
|
+
}
|
73
|
+
})
|
74
|
+
|
75
|
+
# Yield the result message
|
76
|
+
yield data
|
77
|
+
end
|
78
|
+
rescue JSON::ParserError
|
79
|
+
raise CLIJSONDecodeError.new(
|
80
|
+
"Failed to parse JSON from Claude Code",
|
81
|
+
line: output
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def find_cli_path
|
89
|
+
# Check if claude-code or claude is in PATH
|
90
|
+
%w[claude-code claude].each do |name|
|
91
|
+
path = `which #{name} 2>/dev/null`.chomp
|
92
|
+
return path unless path.empty?
|
93
|
+
end
|
94
|
+
|
95
|
+
# Check common installation locations
|
96
|
+
common_paths = [
|
97
|
+
File.expand_path("~/bin/claude-code"),
|
98
|
+
File.expand_path("~/bin/claude"),
|
99
|
+
"/usr/local/bin/claude-code",
|
100
|
+
"/usr/local/bin/claude",
|
101
|
+
"/opt/claude-code/bin/claude-code"
|
102
|
+
]
|
103
|
+
|
104
|
+
common_paths.find { |p| File.executable?(p) }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
require "json"
|
5
|
+
require "stringio"
|
6
|
+
|
7
|
+
module ClaudeCodeSDK
|
8
|
+
module Transport
|
9
|
+
class SubprocessCLI < Base
|
10
|
+
BUFFER_SIZE = 1024 * 1024 # 1MB
|
11
|
+
STDERR_TIMEOUT = 5 # seconds
|
12
|
+
|
13
|
+
def initialize(prompt:, options: nil)
|
14
|
+
@prompt = prompt
|
15
|
+
@options = options || Options.new
|
16
|
+
@process = nil
|
17
|
+
@stdin = nil
|
18
|
+
@stdout = nil
|
19
|
+
@stderr = nil
|
20
|
+
@wait_thread = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect
|
24
|
+
return if @connected
|
25
|
+
|
26
|
+
cli_path = find_cli_path
|
27
|
+
raise CLINotFoundError.new(cli_path: cli_path) unless cli_path
|
28
|
+
|
29
|
+
args = @options.to_cli_args
|
30
|
+
args.push("--print", @prompt) # Add prompt after --print
|
31
|
+
|
32
|
+
command = [cli_path] + args
|
33
|
+
puts "[DEBUG] Command: #{command.join(" ")}" if ENV["DEBUG"]
|
34
|
+
|
35
|
+
env = { "ANTHROPIC_API_KEY" => ENV.fetch("ANTHROPIC_API_KEY", nil) }
|
36
|
+
env["CLAUDE_CODE_ENTRYPOINT"] = "sdk-ruby"
|
37
|
+
|
38
|
+
popen_options = { chdir: @options.cwd }.compact
|
39
|
+
@stdin, @stdout, @stderr, @wait_thread = Open3.popen3(env, *command, **popen_options)
|
40
|
+
@stdin.close # Close stdin since we pass all data via args
|
41
|
+
@connected = true
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
raise CLINotFoundError.new("Claude Code CLI not found", cli_path: cli_path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def disconnect
|
47
|
+
return unless @connected
|
48
|
+
|
49
|
+
@stdin&.close unless @stdin&.closed?
|
50
|
+
@stdout&.close unless @stdout&.closed?
|
51
|
+
@stderr&.close unless @stderr&.closed?
|
52
|
+
|
53
|
+
if @wait_thread&.alive?
|
54
|
+
begin
|
55
|
+
Process.kill("TERM", @wait_thread.pid)
|
56
|
+
@wait_thread.join(5)
|
57
|
+
rescue Errno::ESRCH
|
58
|
+
# Process already finished
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@process = nil
|
63
|
+
@connected = false
|
64
|
+
end
|
65
|
+
|
66
|
+
def connected?
|
67
|
+
@connected && @wait_thread&.alive?
|
68
|
+
rescue Errno::ESRCH
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
def receive_messages
|
73
|
+
connect unless @connected
|
74
|
+
|
75
|
+
json_buffer = ""
|
76
|
+
|
77
|
+
# Read streaming JSON from stdout
|
78
|
+
puts "[DEBUG] Reading streaming JSON..." if ENV["DEBUG"]
|
79
|
+
|
80
|
+
begin
|
81
|
+
@stdout.each_line do |line|
|
82
|
+
line_str = line.strip
|
83
|
+
next if line_str.empty?
|
84
|
+
|
85
|
+
puts "[DEBUG] Read line: #{line_str}" if ENV["DEBUG"]
|
86
|
+
|
87
|
+
json_buffer += line_str
|
88
|
+
|
89
|
+
begin
|
90
|
+
data = JSON.parse(json_buffer, symbolize_names: true)
|
91
|
+
json_buffer = ""
|
92
|
+
puts "[DEBUG] Parsed message: #{data[:type]}" if ENV["DEBUG"]
|
93
|
+
yield data
|
94
|
+
rescue JSON::ParserError
|
95
|
+
# Continue accumulating until we have valid JSON
|
96
|
+
next
|
97
|
+
end
|
98
|
+
end
|
99
|
+
rescue IOError => e
|
100
|
+
puts "[DEBUG] IOError reading stdout: #{e.message}" if ENV["DEBUG"]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Handle process completion
|
104
|
+
puts "[DEBUG] Waiting for process to complete..." if ENV["DEBUG"]
|
105
|
+
@wait_thread.join
|
106
|
+
exit_status = @wait_thread.value.exitstatus
|
107
|
+
|
108
|
+
puts "[DEBUG] Process exited with status: #{exit_status}" if ENV["DEBUG"]
|
109
|
+
|
110
|
+
unless exit_status.zero?
|
111
|
+
stderr_output = @stderr.read
|
112
|
+
puts "[DEBUG] stderr: #{stderr_output}" if ENV["DEBUG"]
|
113
|
+
raise ProcessError.new(
|
114
|
+
"Claude Code process failed",
|
115
|
+
exit_code: exit_status,
|
116
|
+
stderr: stderr_output
|
117
|
+
)
|
118
|
+
end
|
119
|
+
ensure
|
120
|
+
disconnect
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def find_cli_path
|
126
|
+
# Check if claude-code or claude is in PATH
|
127
|
+
%w[claude-code claude].each do |name|
|
128
|
+
path = `which #{name} 2>/dev/null`.chomp
|
129
|
+
return path unless path.empty?
|
130
|
+
end
|
131
|
+
|
132
|
+
# Check common installation locations
|
133
|
+
common_paths = [
|
134
|
+
File.expand_path("~/bin/claude-code"),
|
135
|
+
File.expand_path("~/bin/claude"),
|
136
|
+
"/usr/local/bin/claude-code",
|
137
|
+
"/usr/local/bin/claude",
|
138
|
+
"/opt/claude-code/bin/claude-code"
|
139
|
+
]
|
140
|
+
|
141
|
+
common_paths.find { |p| File.executable?(p) }
|
142
|
+
end
|
143
|
+
|
144
|
+
def read_stderr_with_timeout
|
145
|
+
content = StringIO.new
|
146
|
+
start_time = Time.now
|
147
|
+
|
148
|
+
while (Time.now - start_time) < STDERR_TIMEOUT
|
149
|
+
begin
|
150
|
+
chunk = @stderr.read_nonblock(1024)
|
151
|
+
content.write(chunk)
|
152
|
+
|
153
|
+
# Stop if buffer is too large
|
154
|
+
break if content.size > BUFFER_SIZE
|
155
|
+
rescue IO::WaitReadable
|
156
|
+
# No data available, check if we should continue
|
157
|
+
break unless @stderr.wait_readable(0.1)
|
158
|
+
rescue EOFError
|
159
|
+
break
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
content.string
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClaudeCodeSDK
|
4
|
+
# Options for configuring Claude Code queries
|
5
|
+
class Options
|
6
|
+
attr_accessor :allowed_tools, :blocked_tools, :permission_mode,
|
7
|
+
:max_thinking_tokens, :system_prompt, :cwd,
|
8
|
+
:mcp_servers, :disable_cache, :no_markdown,
|
9
|
+
:tree, :tree_symlinks, :tree_verbose,
|
10
|
+
:max_turns, :model, :continue_conversation,
|
11
|
+
:resume, :append_system_prompt
|
12
|
+
|
13
|
+
def initialize(**kwargs)
|
14
|
+
@allowed_tools = kwargs[:allowed_tools] || []
|
15
|
+
@blocked_tools = kwargs[:blocked_tools] || []
|
16
|
+
@permission_mode = kwargs[:permission_mode] || "default"
|
17
|
+
@max_thinking_tokens = kwargs[:max_thinking_tokens] || 8000
|
18
|
+
@system_prompt = kwargs[:system_prompt]
|
19
|
+
@cwd = kwargs[:cwd]
|
20
|
+
@mcp_servers = kwargs[:mcp_servers] || {}
|
21
|
+
@disable_cache = kwargs[:disable_cache] || false
|
22
|
+
@no_markdown = kwargs[:no_markdown] || false
|
23
|
+
@tree = kwargs[:tree] || []
|
24
|
+
@tree_symlinks = kwargs[:tree_symlinks] || false
|
25
|
+
@tree_verbose = kwargs[:tree_verbose] || false
|
26
|
+
@max_turns = kwargs[:max_turns]
|
27
|
+
@model = kwargs[:model]
|
28
|
+
@continue_conversation = kwargs[:continue_conversation] || false
|
29
|
+
@resume = kwargs[:resume]
|
30
|
+
@append_system_prompt = kwargs[:append_system_prompt]
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_cli_args
|
34
|
+
args = ["--output-format", "stream-json", "--verbose"]
|
35
|
+
|
36
|
+
args.push("--system-prompt", system_prompt) if system_prompt
|
37
|
+
args.push("--append-system-prompt", append_system_prompt) if append_system_prompt
|
38
|
+
args.push("--allowedTools", allowed_tools.join(",")) unless allowed_tools.empty?
|
39
|
+
args.push("--disallowedTools", blocked_tools.join(",")) unless blocked_tools.empty?
|
40
|
+
args.push("--max-turns", max_turns.to_s) if max_turns
|
41
|
+
args.push("--model", model) if model
|
42
|
+
args.push("--permission-mode", permission_mode) if permission_mode
|
43
|
+
args.push("--continue") if continue_conversation
|
44
|
+
args.push("--resume", resume) if resume
|
45
|
+
args.push("--add-dir", cwd.to_s) if cwd
|
46
|
+
|
47
|
+
unless mcp_servers.empty?
|
48
|
+
require "json"
|
49
|
+
mcp_config = { mcpServers: mcp_servers }.to_json
|
50
|
+
args.push("--mcp-config", mcp_config)
|
51
|
+
end
|
52
|
+
|
53
|
+
args
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Permission modes
|
58
|
+
module PermissionMode
|
59
|
+
DEFAULT = "default"
|
60
|
+
ACCEPT_EDITS = "acceptEdits"
|
61
|
+
BYPASS_PERMISSIONS = "bypassPermissions"
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require_relative "claude_code_sdk/version"
|
5
|
+
require_relative "claude_code_sdk/errors"
|
6
|
+
require_relative "claude_code_sdk/types"
|
7
|
+
require_relative "claude_code_sdk/messages"
|
8
|
+
require_relative "claude_code_sdk/configuration"
|
9
|
+
require_relative "claude_code_sdk/transport/base"
|
10
|
+
require_relative "claude_code_sdk/transport/subprocess_cli"
|
11
|
+
require_relative "claude_code_sdk/internal/client"
|
12
|
+
|
13
|
+
module ClaudeCodeSDK
|
14
|
+
# Set environment variable for SDK identification
|
15
|
+
ENV["CLAUDE_CODE_SDK"] = "ruby/#{VERSION}"
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Query Claude Code with a prompt
|
19
|
+
#
|
20
|
+
# @param prompt [String] The prompt to send to Claude
|
21
|
+
# @param options [ClaudeCodeSDK::Options, Hash, nil] Configuration options
|
22
|
+
# @yield [Message] Messages from the conversation
|
23
|
+
# @return [Array<Message>] All messages if no block given
|
24
|
+
#
|
25
|
+
# @example With a block
|
26
|
+
# ClaudeCodeSDK.query("Hello Claude") do |message|
|
27
|
+
# puts message.text if message.is_a?(AssistantMessage)
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @example Without a block
|
31
|
+
# messages = ClaudeCodeSDK.query("Hello Claude")
|
32
|
+
# messages.each { |msg| puts msg }
|
33
|
+
#
|
34
|
+
# @example With options
|
35
|
+
# ClaudeCodeSDK.query("Help me code",
|
36
|
+
# system_prompt: "You are a Ruby expert",
|
37
|
+
# allowed_tools: ["read_file", "write_file"]
|
38
|
+
# )
|
39
|
+
def query(prompt, options = nil, &block)
|
40
|
+
# Convert hash to Options if needed
|
41
|
+
options = Options.new(**options) if options.is_a?(Hash)
|
42
|
+
|
43
|
+
client = Internal::Client.new
|
44
|
+
|
45
|
+
if block_given?
|
46
|
+
client.query(prompt: prompt, options: options, &block)
|
47
|
+
else
|
48
|
+
messages = []
|
49
|
+
client.query(prompt: prompt, options: options) { |msg| messages << msg }
|
50
|
+
messages
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Convenience method for simple text queries
|
55
|
+
#
|
56
|
+
# @param prompt [String] The prompt to send
|
57
|
+
# @return [String] The concatenated text response
|
58
|
+
def ask(prompt)
|
59
|
+
response_text = []
|
60
|
+
|
61
|
+
query(prompt) do |message|
|
62
|
+
if message.is_a?(AssistantMessage)
|
63
|
+
message.content.each do |block|
|
64
|
+
response_text << block.text if block.is_a?(Content::TextBlock)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
response_text.join("\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Configure global defaults
|
73
|
+
#
|
74
|
+
# @yield [Configuration] The configuration object
|
75
|
+
# @example
|
76
|
+
# ClaudeCodeSDK.configure do |config|
|
77
|
+
# config.default_system_prompt = "You are helpful"
|
78
|
+
# config.default_cwd = "/home/user/projects"
|
79
|
+
# end
|
80
|
+
def configure
|
81
|
+
yield Configuration.instance
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: claude_code_sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tanooki Labs LLC
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: zeitwerk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.14'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.14'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.13'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.50'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.50'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.6'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.6'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2.20'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '2.20'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.22'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.22'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: webmock
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '3.19'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '3.19'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.9'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.9'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: async
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '2.0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '2.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: sorbet-runtime
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0.5'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0.5'
|
195
|
+
description: A Ruby port of the official Python SDK for Claude Code. This gem provides
|
196
|
+
a clean, idiomatic Ruby interface for interacting with Anthropic's Claude Code AI
|
197
|
+
assistant through the command-line interface.
|
198
|
+
email:
|
199
|
+
- hello@tanookilabs.com
|
200
|
+
executables: []
|
201
|
+
extensions: []
|
202
|
+
extra_rdoc_files: []
|
203
|
+
files:
|
204
|
+
- ".rspec"
|
205
|
+
- ".rubocop.yml"
|
206
|
+
- ".yardopts"
|
207
|
+
- CHANGELOG.md
|
208
|
+
- CLAUDE.md
|
209
|
+
- CONTRIBUTING.md
|
210
|
+
- LICENSE
|
211
|
+
- README.md
|
212
|
+
- Rakefile
|
213
|
+
- claude_code_sdk.gemspec
|
214
|
+
- examples/debug_process.rb
|
215
|
+
- examples/debug_query.rb
|
216
|
+
- examples/simple_query.rb
|
217
|
+
- examples/simple_test.rb
|
218
|
+
- examples/simple_tools.rb
|
219
|
+
- examples/simple_tools_fixed.rb
|
220
|
+
- examples/streaming_responses.rb
|
221
|
+
- examples/test_sdk.rb
|
222
|
+
- examples/with_tools.rb
|
223
|
+
- lib/claude_code_sdk.rb
|
224
|
+
- lib/claude_code_sdk/configuration.rb
|
225
|
+
- lib/claude_code_sdk/errors.rb
|
226
|
+
- lib/claude_code_sdk/internal/client.rb
|
227
|
+
- lib/claude_code_sdk/messages.rb
|
228
|
+
- lib/claude_code_sdk/transport/base.rb
|
229
|
+
- lib/claude_code_sdk/transport/simple_cli.rb
|
230
|
+
- lib/claude_code_sdk/transport/subprocess_cli.rb
|
231
|
+
- lib/claude_code_sdk/types.rb
|
232
|
+
- lib/claude_code_sdk/version.rb
|
233
|
+
homepage: https://github.com/TanookiLabs/claude-code-sdk-ruby
|
234
|
+
licenses:
|
235
|
+
- MIT
|
236
|
+
metadata:
|
237
|
+
homepage_uri: https://github.com/TanookiLabs/claude-code-sdk-ruby
|
238
|
+
source_code_uri: https://github.com/TanookiLabs/claude-code-sdk-ruby
|
239
|
+
changelog_uri: https://github.com/TanookiLabs/claude-code-sdk-ruby/blob/main/CHANGELOG.md
|
240
|
+
documentation_uri: https://www.rubydoc.info/gems/claude_code_sdk
|
241
|
+
bug_tracker_uri: https://github.com/TanookiLabs/claude-code-sdk-ruby/issues
|
242
|
+
rubygems_mfa_required: 'true'
|
243
|
+
post_install_message:
|
244
|
+
rdoc_options: []
|
245
|
+
require_paths:
|
246
|
+
- lib
|
247
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
248
|
+
requirements:
|
249
|
+
- - ">="
|
250
|
+
- !ruby/object:Gem::Version
|
251
|
+
version: 3.0.0
|
252
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
253
|
+
requirements:
|
254
|
+
- - ">="
|
255
|
+
- !ruby/object:Gem::Version
|
256
|
+
version: '0'
|
257
|
+
requirements: []
|
258
|
+
rubygems_version: 3.4.10
|
259
|
+
signing_key:
|
260
|
+
specification_version: 4
|
261
|
+
summary: Ruby SDK for Claude Code - AI-powered coding assistant
|
262
|
+
test_files: []
|