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.
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClaudeCodeSDK
4
+ VERSION = "0.1.0"
5
+ 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: []