Class: Legion::TTY::App

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/tty/app.rb

Overview

rubocop:disable Metrics/ClassLength

Constant Summary collapse

CONFIG_DIR =
File.expand_path('~/.legionio/settings')

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_dir: CONFIG_DIR, skip_rain: false) ⇒ App

Returns a new instance of App.



37
38
39
40
41
42
43
44
45
# File 'lib/legion/tty/app.rb', line 37

def initialize(config_dir: CONFIG_DIR, skip_rain: false)
  @config_dir = config_dir
  @skip_rain = skip_rain
  @config = load_config
  @credentials = load_credentials
  @screen_manager = ScreenManager.new
  @hotkeys = Hotkeys.new
  @llm_chat = nil
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



16
17
18
# File 'lib/legion/tty/app.rb', line 16

def config
  @config
end

#credentialsObject (readonly)

Returns the value of attribute credentials.



16
17
18
# File 'lib/legion/tty/app.rb', line 16

def credentials
  @credentials
end

#hotkeysObject (readonly)

Returns the value of attribute hotkeys.



16
17
18
# File 'lib/legion/tty/app.rb', line 16

def hotkeys
  @hotkeys
end

#llm_chatObject (readonly)

Returns the value of attribute llm_chat.



16
17
18
# File 'lib/legion/tty/app.rb', line 16

def llm_chat
  @llm_chat
end

#screen_managerObject (readonly)

Returns the value of attribute screen_manager.



16
17
18
# File 'lib/legion/tty/app.rb', line 16

def screen_manager
  @screen_manager
end

Class Method Details

.first_run?(config_dir: CONFIG_DIR) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/legion/tty/app.rb', line 33

def self.first_run?(config_dir: CONFIG_DIR)
  !File.exist?(File.join(config_dir, 'identity.json'))
end

.parse_argv(argv) ⇒ Object



27
28
29
30
31
# File 'lib/legion/tty/app.rb', line 27

def self.parse_argv(argv)
  opts = {}
  opts[:skip_rain] = true if argv.include?('--skip-rain')
  opts
end

.run(argv = []) ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/legion/tty/app.rb', line 18

def self.run(argv = [])
  opts = parse_argv(argv)
  app = new(**opts)
  app.start
rescue Interrupt => e
  Legion::Logging.debug("app interrupted: #{e.message}") if defined?(Legion::Logging)
  app&.shutdown
end

Instance Method Details

#rescan_environmentObject

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/legion/tty/app.rb', line 101

def rescan_environment
  identity_path = File.join(@config_dir, 'identity.json')
  return unless File.exist?(identity_path)

  Thread.new do
    scanner = Background::Scanner.new
    scan = scanner.scan_all
    identity = deep_symbolize(::JSON.parse(File.read(identity_path)))
    services = scan[:services]&.values&.select { |s| s[:running] }&.map { |s| s[:name] } || []
    repos = scan[:repos]&.map { |r| { name: r[:name], language: r[:language] } } || []
    identity[:environment] = {
      running_services: services,
      repos_count: repos.size,
      top_languages: repos.filter_map { |r| r[:language] }.tally.sort_by { |_, v| -v }.first(5).to_h
    }.compact
    File.write(identity_path, ::JSON.generate(identity))
    @config = load_config
  rescue StandardError => e
    Legion::Logging.warn("rescan_environment failed: #{e.message}") if defined?(Legion::Logging)
    nil
  end
end

#run_chatObject



84
85
86
87
88
89
90
# File 'lib/legion/tty/app.rb', line 84

def run_chat
  rescan_environment
  setup_llm
  chat = Screens::Chat.new(self)
  @screen_manager.push(chat)
  chat.run
end

#run_onboardingObject



75
76
77
78
79
80
81
82
# File 'lib/legion/tty/app.rb', line 75

def run_onboarding
  onboarding = Screens::Onboarding.new(self, skip_rain: @skip_rain)
  data = onboarding.activate
  save_config(data)
  @config = load_config
  @credentials = load_credentials
  run_chat
end

#save_config(data) ⇒ Object

rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



126
127
128
129
130
# File 'lib/legion/tty/app.rb', line 126

def save_config(data)
  FileUtils.mkdir_p(@config_dir)
  save_identity(data)
  save_credentials(data)
end

#setup_hotkeysObject



56
57
58
59
60
61
62
# File 'lib/legion/tty/app.rb', line 56

def setup_hotkeys
  @hotkeys.register("\x04", 'Toggle dashboard (Ctrl+D)') { toggle_dashboard }
  @hotkeys.register("\x0C", 'Refresh screen (Ctrl+L)') { :refresh }
  @hotkeys.register("\x0B", 'Command palette (Ctrl+K)') { :command_palette }
  @hotkeys.register("\x13", 'Session picker (Ctrl+S)') { :session_picker }
  @hotkeys.register("\e", 'Go back (Escape)') { :escape }
end

#setup_llmObject



92
93
94
95
96
97
98
# File 'lib/legion/tty/app.rb', line 92

def setup_llm
  boot_legion_subsystems
  @llm_chat = try_settings_llm
rescue StandardError => e
  Legion::Logging.warn("setup_llm failed: #{e.message}") if defined?(Legion::Logging)
  @llm_chat = nil
end

#shutdownObject



132
133
134
# File 'lib/legion/tty/app.rb', line 132

def shutdown
  @screen_manager.teardown_all
end

#startObject



47
48
49
50
51
52
53
54
# File 'lib/legion/tty/app.rb', line 47

def start
  setup_hotkeys
  if self.class.first_run?(config_dir: @config_dir)
    run_onboarding
  else
    run_chat
  end
end

#toggle_dashboardObject



64
65
66
67
68
69
70
71
72
73
# File 'lib/legion/tty/app.rb', line 64

def toggle_dashboard
  active = @screen_manager.active_screen
  if active.is_a?(Screens::Dashboard)
    @screen_manager.pop
  else
    require_relative 'screens/dashboard'
    dashboard = Screens::Dashboard.new(self)
    @screen_manager.push(dashboard)
  end
end