Class: RubynCode::IDE::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/ide/server.rb

Overview

JSON-RPC 2.0 server for the VS Code extension.

Reads newline-delimited JSON from $stdin, dispatches each request to a handler, and writes JSON-RPC responses/notifications to $stdout. All debug output goes to $stderr — never protocol data.

Processes one request at a time on the main thread.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(permission_mode: :default, yolo: false, workspace_path: nil) ⇒ Server

Returns a new instance of Server.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rubyn_code/ide/server.rb', line 24

def initialize(permission_mode: :default, yolo: false, workspace_path: nil)
  @permission_mode = yolo ? :bypass : permission_mode.to_sym
  @running = false
  @write_mutex = Mutex.new
  @handlers = {}
  @handler_instances = {}
  @workspace_path = nil
  @extension_version = nil
  @client_capabilities = {}
  @session_persistence = nil
  @tool_output_adapter = nil
  @ide_client = Client.new(self)
  @interview_sessions = {}

  apply_initial_workspace(workspace_path)

  Handlers.register_all(self)
end

Instance Attribute Details

#client_capabilitiesObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def client_capabilities
  @client_capabilities
end

#extension_versionObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def extension_version
  @extension_version
end

#handler_instancesObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def handler_instances
  @handler_instances
end

#ide_clientObject (readonly)

Returns the value of attribute ide_client.



22
23
24
# File 'lib/rubyn_code/ide/server.rb', line 22

def ide_client
  @ide_client
end

#permission_modeObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def permission_mode
  @permission_mode
end

#session_persistenceObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def session_persistence
  @session_persistence
end

#tool_output_adapterObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def tool_output_adapter
  @tool_output_adapter
end

#workspace_pathObject

Attributes set by handlers during the session lifecycle.



19
20
21
# File 'lib/rubyn_code/ide/server.rb', line 19

def workspace_path
  @workspace_path
end

Instance Method Details

#apply_initial_workspace(path) ⇒ Object

Adopt a workspace path supplied on the command line (–dir). Done before the ‘initialize` JSON-RPC handshake so tools that resolve their project_root at construction time don’t fall back to Dir.pwd — which in some launch contexts (Docker, double-clicked VS Code on macOS) is something useless like ‘/app` or `/`.



64
65
66
67
68
69
70
71
72
73
# File 'lib/rubyn_code/ide/server.rb', line 64

def apply_initial_workspace(path)
  return unless path && !path.empty?

  if Dir.exist?(path)
    Dir.chdir(path)
    @workspace_path = path
  else
    warn "[IDE::Server] --dir path does not exist, ignoring: #{path}"
  end
end

#drop_interview_session(session_id) ⇒ Object



55
56
57
# File 'lib/rubyn_code/ide/server.rb', line 55

def drop_interview_session(session_id)
  @interview_sessions.delete(session_id)
end

#handler_instance(short_name) ⇒ Object

Look up a handler instance by its short name (e.g. :prompt, :cancel). Returns nil if the handler is not registered.



107
108
109
110
111
112
# File 'lib/rubyn_code/ide/server.rb', line 107

def handler_instance(short_name)
  method_name = Handlers::SHORT_NAMES[short_name.to_sym]
  return nil unless method_name

  @handler_instances[method_name]
end

#lookup_interview_session(session_id) ⇒ Object



51
52
53
# File 'lib/rubyn_code/ide/server.rb', line 51

def lookup_interview_session(session_id)
  @interview_sessions[session_id]
end

#notify(method, params = {}) ⇒ Object

Send a JSON-RPC notification (no id) to stdout.



95
96
97
# File 'lib/rubyn_code/ide/server.rb', line 95

def notify(method, params = {})
  write(Protocol.notification(method, params))
end

#on(method, &block) ⇒ Object

Register a handler for a given JSON-RPC method. The block receives (params, id) and must return a result hash.



101
102
103
# File 'lib/rubyn_code/ide/server.rb', line 101

def on(method, &block)
  @handlers[method] = block
end

#register_interview_session(session) ⇒ Object

── Interview session registry ──────────────────────────────────Owned by the IDE Server so handlers can look up the same session across start / answer / cancel JSON-RPC calls.



47
48
49
# File 'lib/rubyn_code/ide/server.rb', line 47

def register_interview_session(session)
  @interview_sessions[session.session_id] = session
end

#runObject



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rubyn_code/ide/server.rb', line 80

def run
  @running = true
  setup_signal_traps!

  warn "[IDE::Server] started (pid=#{Process.pid})"
  $stdout.sync = true

  read_loop
ensure
  graceful_shutdown!
end

#stop!Object

Signal the server to stop its read loop.



115
116
117
# File 'lib/rubyn_code/ide/server.rb', line 115

def stop!
  @running = false
end

#yoloObject

Backward-compatible reader: true when permission_mode is :bypass.



76
77
78
# File 'lib/rubyn_code/ide/server.rb', line 76

def yolo
  @permission_mode == :bypass
end