legionio 1.4.51 → 1.4.52
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/legion/cli/dashboard/data_fetcher.rb +48 -0
- data/lib/legion/cli/dashboard/renderer.rb +72 -0
- data/lib/legion/cli/dashboard_command.rb +40 -0
- data/lib/legion/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08a5e7057699e03532d0815dc93823ed321ea0f5767915033b10ca5aa75afb40'
|
|
4
|
+
data.tar.gz: bf1311709df94b55812ba9e53360b456b3b80cd1d1bed0450fe7a1b33d5e04c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c44772264edc55cf816923a596d5092f43394dcd292884eadbddc0b88d09e25cb17a75cab374ee3dfffe046e81edd142728bc4647f2ab2c6a3edcc67f1729bc6
|
|
7
|
+
data.tar.gz: '096080ad2b1b2a9103d262ba2547c9442249a08505bf86b60a88927820a00528ba2cc6fed53e9ee9f330202631834b14dc017df394215abdddfaff38d4851887'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.52] - 2026-03-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `legion dashboard`: TUI operational dashboard with auto-refresh polling
|
|
7
|
+
- `Dashboard::DataFetcher`: polls REST API for workers, health, and recent events
|
|
8
|
+
- `Dashboard::Renderer`: terminal-based dashboard rendering with sections for workers, events, health
|
|
9
|
+
- Configurable API URL (`--url`) and refresh interval (`--refresh`)
|
|
10
|
+
|
|
3
11
|
## [1.4.51] - 2026-03-17
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module CLI
|
|
7
|
+
module Dashboard
|
|
8
|
+
class DataFetcher
|
|
9
|
+
def initialize(base_url: 'http://localhost:4567')
|
|
10
|
+
@base_url = base_url
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def workers
|
|
14
|
+
fetch('/api/workers') || []
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def health
|
|
18
|
+
fetch('/api/health') || {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def recent_events(limit: 10)
|
|
22
|
+
fetch("/api/events/recent?limit=#{limit}") || []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def summary
|
|
26
|
+
{
|
|
27
|
+
workers: workers,
|
|
28
|
+
health: health,
|
|
29
|
+
events: recent_events,
|
|
30
|
+
fetched_at: Time.now
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def fetch(path)
|
|
37
|
+
uri = URI("#{@base_url}#{path}")
|
|
38
|
+
response = Net::HTTP.get_response(uri)
|
|
39
|
+
return nil unless response.is_a?(Net::HTTPSuccess)
|
|
40
|
+
|
|
41
|
+
Legion::JSON.load(response.body)
|
|
42
|
+
rescue StandardError
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module CLI
|
|
5
|
+
module Dashboard
|
|
6
|
+
class Renderer
|
|
7
|
+
def initialize(width: nil)
|
|
8
|
+
@width = width || default_width
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def render(data)
|
|
12
|
+
lines = []
|
|
13
|
+
lines << header_line(data)
|
|
14
|
+
lines << separator
|
|
15
|
+
lines << workers_section(data[:workers] || [])
|
|
16
|
+
lines << separator
|
|
17
|
+
lines << events_section(data[:events] || [])
|
|
18
|
+
lines << separator
|
|
19
|
+
lines << health_section(data[:health] || {})
|
|
20
|
+
lines << footer_line(data[:fetched_at])
|
|
21
|
+
lines.flatten.join("\n")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def default_width
|
|
27
|
+
defined?(TTY::Screen) ? TTY::Screen.width : 80
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def header_line(data)
|
|
31
|
+
workers = data[:workers]&.size || 0
|
|
32
|
+
"Legion Dashboard | Workers: #{workers} | #{Time.now.strftime('%H:%M:%S')}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def separator
|
|
36
|
+
'-' * @width
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def workers_section(workers)
|
|
40
|
+
lines = ['Active Workers:']
|
|
41
|
+
workers.first(5).each do |w|
|
|
42
|
+
id = w[:worker_id] || w[:id] || 'unknown'
|
|
43
|
+
status = w[:status] || w[:lifecycle_state] || 'unknown'
|
|
44
|
+
lines << " #{id.to_s.ljust(20)} #{status.to_s.ljust(10)}"
|
|
45
|
+
end
|
|
46
|
+
lines << ' (none)' if workers.empty?
|
|
47
|
+
lines
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def events_section(events)
|
|
51
|
+
lines = ['Recent Events:']
|
|
52
|
+
events.first(5).each do |e|
|
|
53
|
+
time = e[:timestamp] || e[:created_at] || ''
|
|
54
|
+
name = e[:event_name] || e[:name] || ''
|
|
55
|
+
lines << " #{time.to_s[11..18]} #{name}"
|
|
56
|
+
end
|
|
57
|
+
lines << ' (none)' if events.empty?
|
|
58
|
+
lines
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def health_section(health)
|
|
62
|
+
components = health.map { |k, v| "#{k}: #{v}" }.join(' | ')
|
|
63
|
+
"Health: #{components.empty? ? 'unknown' : components}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def footer_line(fetched_at)
|
|
67
|
+
"Last updated: #{fetched_at&.strftime('%H:%M:%S') || 'never'} | Press q to quit, r to refresh"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module CLI
|
|
7
|
+
class DashboardCommand < Thor
|
|
8
|
+
namespace 'dashboard'
|
|
9
|
+
|
|
10
|
+
desc 'start', 'Launch the TUI dashboard'
|
|
11
|
+
option :url, type: :string, default: 'http://localhost:4567', desc: 'API base URL'
|
|
12
|
+
option :refresh, type: :numeric, default: 2, desc: 'Refresh interval in seconds'
|
|
13
|
+
def start
|
|
14
|
+
require 'legion/cli/dashboard/data_fetcher'
|
|
15
|
+
require 'legion/cli/dashboard/renderer'
|
|
16
|
+
|
|
17
|
+
fetcher = Dashboard::DataFetcher.new(base_url: options[:url])
|
|
18
|
+
renderer = Dashboard::Renderer.new
|
|
19
|
+
|
|
20
|
+
puts 'Starting dashboard... (press q to quit)'
|
|
21
|
+
loop do
|
|
22
|
+
system('clear') || system('cls')
|
|
23
|
+
data = fetcher.summary
|
|
24
|
+
puts renderer.render(data)
|
|
25
|
+
|
|
26
|
+
ready = $stdin.wait_readable(options[:refresh])
|
|
27
|
+
if ready
|
|
28
|
+
input = $stdin.getc
|
|
29
|
+
break if input == 'q'
|
|
30
|
+
end
|
|
31
|
+
rescue Interrupt
|
|
32
|
+
break
|
|
33
|
+
end
|
|
34
|
+
puts 'Dashboard stopped.'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
default_task :start
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/legion/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legionio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.52
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -401,6 +401,9 @@ files:
|
|
|
401
401
|
- lib/legion/cli/connection.rb
|
|
402
402
|
- lib/legion/cli/cost/data_client.rb
|
|
403
403
|
- lib/legion/cli/cost_command.rb
|
|
404
|
+
- lib/legion/cli/dashboard/data_fetcher.rb
|
|
405
|
+
- lib/legion/cli/dashboard/renderer.rb
|
|
406
|
+
- lib/legion/cli/dashboard_command.rb
|
|
404
407
|
- lib/legion/cli/doctor/bundle_check.rb
|
|
405
408
|
- lib/legion/cli/doctor/cache_check.rb
|
|
406
409
|
- lib/legion/cli/doctor/config_check.rb
|