Class: Antigravity::Connection::LocalConnection

Inherits:
Base
  • Object
show all
Defined in:
lib/antigravity/connection/local_connection.rb

Overview

Manages the full lifecycle of communicating with the localharness Go binary.

Lifecycle: discover → spawn → stdio handshake → WebSocket → events → shutdown

The localharness binary is the core Go engine that powers Antigravity. It handles model calls, tool orchestration, and agent logic. This class is the Ruby adapter that speaks its protocol.

Constant Summary collapse

BINARY_SEARCH_PATHS =

Known locations for the localharness binary (checked in order). IMPORTANT: The standalone localharness binary (from PyPI wheel) uses the stdin/stdout protobuf handshake. The language_server binary (Antigravity.app) does NOT — it's the IDE server mode.

[
  File.expand_path('~/.antigravity/bin/localharness'),
  File.expand_path('~/.local/bin/localharness'),
].freeze
HARNESS_SUBCOMMAND =
'localharness'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

inherited

Methods included from Emojifiable

#emoji, included

Constructor Details

#initialize(binary_path: nil) ⇒ LocalConnection

Returns a new instance of LocalConnection.



30
31
32
33
34
35
36
37
38
39
# File 'lib/antigravity/connection/local_connection.rb', line 30

def initialize(binary_path: nil)
  @binary_path = binary_path || self.class.find_binary!
  @port = nil
  @api_key = nil
  @pid = nil
  @stdin = nil
  @stdout = nil
  @stderr = nil
  @connected = false
end

Instance Attribute Details

#api_keyObject (readonly)

Returns the value of attribute api_key.



28
29
30
# File 'lib/antigravity/connection/local_connection.rb', line 28

def api_key
  @api_key
end

#pidObject (readonly)

Returns the value of attribute pid.



28
29
30
# File 'lib/antigravity/connection/local_connection.rb', line 28

def pid
  @pid
end

#portObject (readonly)

Returns the value of attribute port.



28
29
30
# File 'lib/antigravity/connection/local_connection.rb', line 28

def port
  @port
end

Class Method Details

.find_binary!String

Finds the localharness binary. Search order:

1. ANTIGRAVITY_HARNESS_PATH env var
2. Antigravity.app (macOS)
3. ~/.antigravity/bin/
4. PATH lookup via `which`
5. Auto-download from PyPI (unless ANTIGRAVITY_AUTO_DOWNLOAD=false)

Returns:

  • (String)

    absolute path to the binary

Raises:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/antigravity/connection/local_connection.rb', line 52

def self.find_binary!
  # 1. Env var override
  if (env_path = ENV['ANTIGRAVITY_HARNESS_PATH'])
    return env_path if File.executable?(env_path)

    raise HarnessNotFoundError,
      "ANTIGRAVITY_HARNESS_PATH=#{env_path} is not executable"
  end

  # 2. Known paths
  BINARY_SEARCH_PATHS.each do |path|
    return path if File.executable?(path)
  end

  # 3. PATH lookup
  which_result = `which localharness 2>/dev/null`.strip
  return which_result unless which_result.empty?

  # 4. Auto-download from PyPI wheel (opt-out with ANTIGRAVITY_AUTO_DOWNLOAD=false)
  auto_dl = ENV.fetch('ANTIGRAVITY_AUTO_DOWNLOAD', 'true').downcase
  unless %w[false 0 no].include?(auto_dl)
    $stderr.puts "⏳ localharness not found locally. Downloading from PyPI... this may take a minute."
    return BinaryFetcher.fetch!
  end

  raise HarnessNotFoundError,
    "Could not find localharness binary. Install Antigravity.app, set ANTIGRAVITY_HARNESS_PATH, or allow auto-download."
end

Instance Method Details

#connect!Object

--- Connection Lifecycle ---



83
84
85
86
87
88
89
# File 'lib/antigravity/connection/local_connection.rb', line 83

def connect!
  spawn_process!
  perform_handshake!
  connect_websocket!
  @connected = true
  self
end

#connected?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/antigravity/connection/local_connection.rb', line 91

def connected?
  @connected && process_alive? && @ws_client&.connected?
end

#disconnect!Object



95
96
97
98
99
# File 'lib/antigravity/connection/local_connection.rb', line 95

def disconnect!
  @connected = false
  @ws_client&.close
  kill_process!
end

#ws_clientObject

Expose the WebSocket client for Conversation to use



102
103
104
# File 'lib/antigravity/connection/local_connection.rb', line 102

def ws_client
  @ws_client
end