antigravity-sdk 0.5.4 → 0.5.5

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: 25e15da1171b05a2bcc0be36f79e4f1f6e6e0e6135d520d3776282007071ee05
4
- data.tar.gz: 3ddfcb833bb6d1339573b81e5910f33c37cd4113bfb28c753367386f0d67d88e
3
+ metadata.gz: fff0721cd596c0cafa8734522f4a88f26813dfe9afc71941389cb79bf109cfa4
4
+ data.tar.gz: 0f975b13b784c682519ee0f60e9f0cb574535e819b13e9224bdf3abb74fbc91f
5
5
  SHA512:
6
- metadata.gz: 70112ba04d101d659b82372f4f49f03a301d9d1e8fb4c89de871ccf2abdee7bed7017b3fe8440eff5c935902f0c545238081d2439e7aff1e4ca5a63d76f87e83
7
- data.tar.gz: feb64a14685fefe355772238556f05e27a08aad6f9ad44ae74db4fd0c16e1821eda88f78dbcc24cf990cb90d744139697b06eb883da4fe1f447d67a9d486de7c
6
+ metadata.gz: fe0700f980ab6d196252151616ecb79181efa484ce824d5a65f63e75826536a9800f8a2f49450296a92aace284f1270e243115d1f90055098a95fce4a986c446
7
+ data.tar.gz: 0174bc0e5167c6d406d32f2f3e244e0f4860c2cb6e65237bbe9d591835f05ba8fcf1ab8d501f80e56fb1130c73f93b138f2d3b18c457d2f16e983f4d668bf79f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.4
1
+ 0.5.5
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Diagnostics module for Antigravity SDK.
4
+ # Probes environment, API key, harness binary, gems, and Gemini API models.
5
+ #
6
+ # Usage:
7
+ # Antigravity::Diagnostics.run! # Full colorful output
8
+ # Antigravity::Diagnostics.summary # Returns hash of all data
9
+ # Antigravity::Diagnostics.check_api_key # Just the key check
10
+ #
11
+ module Antigravity
12
+ module Diagnostics
13
+ C = Antigravity::Colors
14
+
15
+ # Main entry point — prints full colorful diagnostic report
16
+ def self.run!(verbose: false)
17
+ data = summary
18
+
19
+ puts ''
20
+ puts C.bold("💎 Antigravity SDK #{C.cyan("v#{data[:sdk_version]}")} — Diagnostics")
21
+ puts C.dim('=' * 56)
22
+
23
+ # Ruby
24
+ puts section('💻 Runtime')
25
+ puts field('Ruby', "#{data[:ruby_version]} (#{data[:ruby_platform]})")
26
+ puts field('Bundler', data[:bundler_version])
27
+ puts field('rv', data[:rv_version] || C.dim('not detected'))
28
+
29
+ # API Key
30
+ puts section('🔑 Authentication')
31
+ if data[:api_key_present]
32
+ masked = data[:api_key_prefix] + '****' + data[:api_key_suffix]
33
+ source = data[:api_key_source]
34
+ puts field('API Key', "#{C.green(masked)} (#{C.dim(source)})")
35
+ else
36
+ puts field('API Key', C.red('⚠️ NOT SET — export GEMINI_API_KEY'))
37
+ end
38
+
39
+ # Model
40
+ puts field('Model', data[:default_model])
41
+ if data[:model_source] == 'default'
42
+ puts C.dim(" └─ using SDK default (set GEMINI_MODEL or ANTIGRAVITY_MODEL to override)")
43
+ end
44
+
45
+ # Harness
46
+ puts section('📦 Harness')
47
+ if data[:harness_exists]
48
+ size_mb = (data[:harness_size] / 1_048_576.0).round(1)
49
+ mtime = data[:harness_mtime]&.strftime('%Y-%m-%d %H:%M') || '?'
50
+ puts field('Path', data[:harness_path])
51
+ puts field('Size', "#{size_mb}MB")
52
+ puts field('Modified', mtime)
53
+ puts field('Arch', data[:harness_arch] || C.dim('unknown'))
54
+ else
55
+ puts field('Path', C.red("⚠️ NOT FOUND at #{data[:harness_path]}"))
56
+ puts C.dim(" └─ run: just harness-fetch")
57
+ end
58
+
59
+ # Gems
60
+ puts section('📚 Dependencies')
61
+ data[:gems].each do |name, ver|
62
+ status = ver ? C.green(ver) : C.red('missing')
63
+ puts field(name, status)
64
+ end
65
+
66
+ # Timeouts
67
+ puts section('⏱️ Timeouts')
68
+ puts field('LLM', "#{data[:timeout_llm]}s")
69
+ puts field('WebSocket', "#{data[:timeout_ws]}s")
70
+ puts field('Handshake', "#{data[:timeout_handshake]}s")
71
+
72
+ # Gemini API models probe (optional, needs network)
73
+ if data[:api_key_present] && verbose
74
+ puts section('🤖 Gemini API Models')
75
+ models = probe_models(data[:api_key_raw])
76
+ if models
77
+ puts field('Available', "#{C.green(models[:count].to_s)} models")
78
+ flash = models[:names].select { |n| n.include?('flash') }.first(3)
79
+ pro = models[:names].select { |n| n.include?('pro') }.first(3)
80
+ puts field('Flash', flash.join(', ')) unless flash.empty?
81
+ puts field('Pro', pro.join(', ')) unless pro.empty?
82
+ else
83
+ puts field('Status', C.yellow('⚠️ Could not reach Gemini API'))
84
+ end
85
+ elsif data[:api_key_present]
86
+ puts C.dim("\n Tip: run with --verbose to probe Gemini API models")
87
+ end
88
+
89
+ # Overall status
90
+ puts ''
91
+ issues = health_check(data)
92
+ if issues.empty?
93
+ puts C.green('✅ All checks passed — ready to go!')
94
+ else
95
+ puts C.yellow("⚠️ #{issues.length} issue(s) found:")
96
+ issues.each { |i| puts C.yellow(" • #{i}") }
97
+ end
98
+ puts ''
99
+
100
+ data
101
+ end
102
+
103
+ # Returns a structured hash of all diagnostic data
104
+ def self.summary
105
+ config = Antigravity.config
106
+ api_key = config.api_key&.strip
107
+
108
+ # Detect API key source
109
+ api_key_source = if ENV['GEMINI_API_KEY'] && !ENV['GEMINI_API_KEY'].empty?
110
+ 'GEMINI_API_KEY'
111
+ else
112
+ '.env or config'
113
+ end
114
+
115
+ # Detect model source
116
+ model_source = if ENV['GEMINI_MODEL'] && !ENV['GEMINI_MODEL'].empty?
117
+ 'GEMINI_MODEL'
118
+ elsif ENV['ANTIGRAVITY_MODEL'] && !ENV['ANTIGRAVITY_MODEL'].empty?
119
+ 'ANTIGRAVITY_MODEL'
120
+ else
121
+ 'default'
122
+ end
123
+
124
+ # Harness binary info
125
+ harness_path = config.harness_path
126
+ harness_stat = File.stat(harness_path) rescue nil
127
+ harness_arch = detect_arch(harness_path) if harness_stat
128
+
129
+ # rv detection
130
+ rv_version = detect_rv
131
+
132
+ # Gem versions — stdlib gems need special detection
133
+ gem_names = %w[websocket dotenv json logger]
134
+ gems = gem_names.to_h do |g|
135
+ ver = Gem.loaded_specs[g]&.version&.to_s
136
+ # Stdlib gems (json, logger) may not appear in loaded_specs
137
+ ver ||= begin
138
+ old_verbose = $VERBOSE
139
+ $VERBOSE = nil
140
+ require g
141
+ $VERBOSE = old_verbose
142
+ defined?(Gem) ? Gem.loaded_specs[g]&.version&.to_s : nil
143
+ rescue LoadError
144
+ nil
145
+ end
146
+ # Last resort: check if the constant exists (stdlib bundled)
147
+ ver ||= '(stdlib)' if %w[json logger].include?(g)
148
+ [g, ver]
149
+ end
150
+
151
+ {
152
+ sdk_version: Antigravity::VERSION,
153
+ ruby_version: RUBY_VERSION,
154
+ ruby_platform: RUBY_PLATFORM,
155
+ bundler_version: Bundler::VERSION,
156
+ rv_version: rv_version,
157
+ api_key_present: api_key && !api_key.empty?,
158
+ api_key_prefix: api_key ? api_key[0..5] : '',
159
+ api_key_suffix: api_key ? api_key[-2..] : '',
160
+ api_key_source: api_key_source,
161
+ api_key_raw: api_key,
162
+ default_model: config.default_model,
163
+ model_source: model_source,
164
+ harness_path: harness_path,
165
+ harness_exists: !harness_stat.nil?,
166
+ harness_size: harness_stat&.size || 0,
167
+ harness_mtime: harness_stat&.mtime,
168
+ harness_arch: harness_arch,
169
+ timeout_llm: config.timeout_llm,
170
+ timeout_ws: config.timeout_ws,
171
+ timeout_handshake: config.timeout_handshake,
172
+ gems: gems,
173
+ }
174
+ end
175
+
176
+ # Quick health check — returns array of issue strings
177
+ def self.health_check(data = nil)
178
+ data ||= summary
179
+ issues = []
180
+ issues << 'GEMINI_API_KEY is not set' unless data[:api_key_present]
181
+ issues << "Harness binary not found at #{data[:harness_path]}" unless data[:harness_exists]
182
+ issues << 'websocket gem not loaded' unless data.dig(:gems, 'websocket')
183
+ issues
184
+ end
185
+
186
+ private
187
+
188
+ def self.section(title)
189
+ "\n#{C.bold(title)}"
190
+ end
191
+
192
+ def self.field(label, value)
193
+ " #{C.cyan(label.to_s.ljust(12))} #{value}"
194
+ end
195
+
196
+ def self.detect_arch(path)
197
+ return nil unless File.exist?(path)
198
+ output = `file '#{path}' 2>/dev/null`.strip
199
+ case output
200
+ when /arm64/ then 'arm64 (Apple Silicon)'
201
+ when /x86_64/ then 'x86_64 (Intel)'
202
+ when /ELF.*64/ then 'linux-amd64'
203
+ else output.split(':').last&.strip&.slice(0, 40)
204
+ end
205
+ rescue
206
+ nil
207
+ end
208
+
209
+ def self.detect_rv
210
+ `rv --version 2>/dev/null`.strip.then { |v| v.empty? ? nil : v }
211
+ rescue
212
+ nil
213
+ end
214
+
215
+ def self.probe_models(api_key)
216
+ require 'net/http'
217
+ require 'json'
218
+ uri = URI("https://generativelanguage.googleapis.com/v1beta/models?key=#{api_key}")
219
+ resp = Net::HTTP.get_response(uri)
220
+ return nil unless resp.is_a?(Net::HTTPSuccess)
221
+ body = JSON.parse(resp.body)
222
+ models = body['models'] || []
223
+ names = models.map { |m| m['name'].to_s.sub('models/', '') }.sort
224
+ { count: names.length, names: names }
225
+ rescue
226
+ nil
227
+ end
228
+ end
229
+ end
data/lib/antigravity.rb CHANGED
@@ -29,6 +29,7 @@ require_relative "antigravity/connection/local_connection"
29
29
  require_relative "antigravity/conversation"
30
30
  require_relative "antigravity/colors"
31
31
  require_relative "antigravity/lifecycle_logger"
32
+ require_relative "antigravity/diagnostics"
32
33
  require_relative "antigravity/agent"
33
34
 
34
35
  module Antigravity
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antigravity-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Riccardo Carlesso
@@ -84,6 +84,7 @@ files:
84
84
  - lib/antigravity/connection/local_connection.rb
85
85
  - lib/antigravity/connection/websocket_client.rb
86
86
  - lib/antigravity/conversation.rb
87
+ - lib/antigravity/diagnostics.rb
87
88
  - lib/antigravity/emojis.rb
88
89
  - lib/antigravity/errors.rb
89
90
  - lib/antigravity/guards.rb