Class: Legion::TTY::Screens::Onboarding

Inherits:
Base
  • Object
show all
Defined in:
lib/legion/tty/screens/onboarding.rb

Overview

rubocop:disable Metrics/ClassLength

Constant Summary collapse

TYPED_DELAY =
0.05

Instance Attribute Summary

Attributes inherited from Base

#app

Instance Method Summary collapse

Methods inherited from Base

#deactivate, #handle_input, #render, #teardown

Constructor Details

#initialize(app, wizard: nil, output: $stdout, skip_rain: false) ⇒ Onboarding

Returns a new instance of Onboarding.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/legion/tty/screens/onboarding.rb', line 20

def initialize(app, wizard: nil, output: $stdout, skip_rain: false)
  super(app)
  @wizard = wizard || Components::WizardPrompt.new
  @output = output
  @skip_rain = skip_rain
  @scan_queue = Queue.new
  @github_queue = Queue.new
  @github_quick_queue = Queue.new
  @kerberos_queue = Queue.new
  @llm_queue = Queue.new
  @bootstrap_queue = Queue.new
  @kerberos_identity = nil
  @github_quick = nil
  @vault_results = nil
  @bootstrap_data = nil
  @log = BootLogger.new
end

Instance Method Details

#activateObject

rubocop:disable Metrics/AbcSize



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/legion/tty/screens/onboarding.rb', line 39

def activate
  @log.log('onboarding', 'activate started')
  start_background_threads
  run_rain unless @skip_rain
  run_intro
  config = run_wizard
  @log.log('wizard', "name=#{config[:name]} provider=#{config[:provider]}")
  collect_bootstrap_result
  run_vault_auth
  scan_data, github_data = collect_background_results
  run_cache_awakening(scan_data)
  run_gaia_awakening
  run_reveal(name: config[:name], scan_data: scan_data, github_data: github_data)
  @log.log('onboarding', 'activate complete')
  build_onboarding_result(config, scan_data, github_data)
end

#build_summary(name:, scan_data:, github_data:) ⇒ Object

rubocop:disable Metrics/AbcSize



255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/legion/tty/screens/onboarding.rb', line 255

def build_summary(name:, scan_data:, github_data:)
  lines = ["Hello, #{name}!", '', "Here's what I found:"]
  lines.concat(bootstrap_summary_lines)
  lines.concat(identity_summary_lines)
  lines.concat(scan_summary_lines(scan_data))
  lines.concat(dotfiles_summary_lines(scan_data))
  lines.concat(github_summary_lines(github_data))
  lines.concat(vault_summary_lines)
  lines.concat(cache_summary_lines(scan_data))
  lines.concat(gaia_summary_lines)
  lines.join("\n")
end

#collect_background_resultsObject

rubocop:enable Metrics/AbcSize, Metrics/MethodLength



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/legion/tty/screens/onboarding.rb', line 220

def collect_background_results
  @log.log('collect', 'waiting for scanner results (10s timeout)')
  scan_result = drain_with_timeout(@scan_queue, timeout: 10)
  scan_data = scan_result&.dig(:data) || { services: {}, repos: [], tools: {} }
  log_scan_data(scan_data)

  # Now launch GitHub probe with discovered remotes
  remotes = scan_data[:repos]&.filter_map { |r| r[:remote] } || []
  @log.log('collect', "launching github probe with #{remotes.size} remotes")
  @github_probe.run_async(@github_queue, remotes: remotes, quick_profile: @github_quick)
  github_result = drain_with_timeout(@github_queue, timeout: 8)
  github_data = github_result&.dig(:data)
  log_github_data(github_data)
  [scan_data, github_data]
end

#detect_providersObject



112
113
114
115
116
117
118
119
120
121
# File 'lib/legion/tty/screens/onboarding.rb', line 112

def detect_providers
  typed_output('Detecting AI providers...')
  @output.puts
  @output.puts
  llm_data = drain_with_timeout(@llm_queue, timeout: 15)
  providers = llm_data&.dig(:data, :providers) || []
  @wizard.display_provider_results(providers)
  @output.puts
  providers
end

#run_cache_awakening(scan_data) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/legion/tty/screens/onboarding.rb', line 151

def run_cache_awakening(scan_data)
  services = scan_data.is_a?(Hash) ? scan_data[:services] : nil
  return unless services.is_a?(Hash)

  if services.dig(:memcached, :running) || services.dig(:redis, :running)
    typed_output('... extending neural pathways...')
    sleep 0.8
    typed_output('Additional memory online.')
  else
    run_cache_offer
  end
  @output.puts
end

#run_cache_offerObject



165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/legion/tty/screens/onboarding.rb', line 165

def run_cache_offer
  typed_output('No extended memory detected.')
  sleep 0.8
  @output.puts
  return unless @wizard.confirm('Shall I activate a memory cache?')

  binary = detect_cache_binary
  if binary
    run_cache_start(binary)
  else
    typed_output('No cache service found. Install with: brew install memcached')
  end
end

#run_cache_start(binary) ⇒ Object



179
180
181
182
183
184
185
186
# File 'lib/legion/tty/screens/onboarding.rb', line 179

def run_cache_start(binary)
  started = start_cache_service(binary.to_s)
  if started
    typed_output('Memory cache activated. Neural capacity expanded.')
  else
    typed_output("No cache service found. Install with: brew install #{binary}")
  end
end

#run_gaia_awakeningObject

rubocop:disable Metrics/AbcSize, Metrics/MethodLength



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/legion/tty/screens/onboarding.rb', line 189

def run_gaia_awakening
  typed_output('Scanning for active cognition threads...')
  sleep 1.2
  @output.puts

  if legionio_running?
    typed_output('GAIA is awake.')
    sleep 0.5
    typed_output('Heuristic mesh: nominal.')
    sleep 0.8
    typed_output('Cognitive threads synchronized.')
  else
    typed_output('GAIA is dormant.')
    sleep 1
    @output.puts
    if @wizard.confirm('Shall I wake her?')
      started = start_legionio_daemon
      if started
        typed_output('... initializing cognitive substrate...')
        sleep 1
        typed_output('GAIA online. All systems nominal.')
      else
        typed_output("Could not start daemon. Run 'legionio start' manually.")
      end
    end
  end

  @output.puts
end

#run_introObject

rubocop:enable Metrics/AbcSize



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/legion/tty/screens/onboarding.rb', line 77

def run_intro
  # Collect background results that ran during the rain
  collect_kerberos_identity
  collect_github_quick

  sleep 2
  typed_output('...')
  sleep 1.2
  @output.puts
  @output.puts
  typed_output("Hello. I'm Legion.")
  @output.puts
  sleep 1.5
  if @kerberos_identity
    run_intro_with_identity
  else
    typed_output("Let's get you set up.")
    @output.puts
    @output.puts
  end
  run_intro_with_github if @github_quick
end

#run_rainObject

rubocop:disable Metrics/AbcSize



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/legion/tty/screens/onboarding.rb', line 58

def run_rain
  require 'tty-cursor'
  require 'tty-font'
  width = terminal_width
  height = terminal_height
  rain = Components::DigitalRain.new(width: width, height: height)
  rain.run(duration_seconds: 20, fps: 18, output: @output)
  @output.print ::TTY::Cursor.clear_screen
  font = ::TTY::Font.new(:standard)
  title = font.write('LEGION')
  title.each_line do |line|
    @output.puts line.center(width)
  end
  @output.puts Theme.c(:muted, 'async cognition engine').center(width + 20)
  sleep 5
  @output.print ::TTY::Cursor.clear_screen
end

#run_reveal(name:, scan_data:, github_data:) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/legion/tty/screens/onboarding.rb', line 236

def run_reveal(name:, scan_data:, github_data:)
  require 'tty-box'
  @output.puts
  typed_output('One moment...')
  @output.puts
  sleep 1.5
  summary = build_summary(name: name, scan_data: scan_data, github_data: github_data)
  box = ::TTY::Box.frame(summary, padding: 1, border: :thick)
  @output.puts box
  @output.puts
  @wizard.confirm('Does this look right?')
  @output.puts
  sleep 0.8
  typed_output("Let's chat.")
  @output.puts
  sleep 1
end

#run_wizardObject



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/legion/tty/screens/onboarding.rb', line 100

def run_wizard
  name = ask_for_name
  sleep 0.8
  typed_output("  Nice to meet you, #{name}.")
  @output.puts
  sleep 1
  providers = detect_providers
  default = select_provider_default(providers)
  @output.puts
  { name: name, provider: default, providers: providers }
end

#select_provider_default(providers) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/legion/tty/screens/onboarding.rb', line 123

def select_provider_default(providers)
  working = providers.select { |p| p[:status] == :ok }
  if working.any?
    default = @wizard.select_default_provider(working)
    sleep 0.5
    typed_output("Connected. Let's chat.")
    default
  else
    typed_output('No AI providers detected. Configure one in ~/.legionio/settings/llm.json')
    nil
  end
end

#start_background_threadsObject



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/legion/tty/screens/onboarding.rb', line 136

def start_background_threads
  @log.log('threads', 'launching scanner, kerberos probe, github quick probe')
  @scanner = Background::Scanner.new(logger: @log)
  @github_probe = Background::GitHubProbe.new(logger: @log)
  @kerberos_probe = Background::KerberosProbe.new(logger: @log)
  @scanner.run_async(@scan_queue)
  @kerberos_probe.run_async(@kerberos_queue)
  @github_probe.run_quick_async(@github_quick_queue)
  require_relative '../background/llm_probe'
  @llm_probe = Background::LlmProbe.new(logger: @log)
  @llm_probe.run_async(@llm_queue)
  @bootstrap_probe = Background::BootstrapConfig.new(logger: @log)
  @bootstrap_probe.run_async(@bootstrap_queue)
end