legionio 1.4.66 → 1.4.67
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/.rubocop.yml +1 -0
- data/CHANGELOG.md +11 -0
- data/lib/legion/cli/detect_command.rb +155 -0
- data/lib/legion/cli/update_command.rb +15 -0
- data/lib/legion/cli.rb +4 -0
- data/lib/legion/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a91ac55fb8db8f7105267bc77653cfd6c1a834a702fe6197a0e3687a889c841b
|
|
4
|
+
data.tar.gz: 7819aaa4e4dadb1e12e7f8741f57549ca6e8e801cc22aa472835c95cc16332df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3d119331cd7741a3a5ec70b31ff224be0c74732334f200a38e4392eefd04cf1dc6846fc34a712ac6c6512f6baf45de9a83e26b8d0be723b14ab23efe05c1797
|
|
7
|
+
data.tar.gz: 3d2b1ff8e85f33cbcbbaceb60d8f60bfc176d23abb6c85c5212fc0ce810aeb588a964b51efef38832c049aa16efd940944da0f872be4e4178f5b611836a11151
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.67] - 2026-03-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `legionio detect` subcommand — scan environment and recommend extensions (requires lex-detect gem)
|
|
7
|
+
- `detect scan` (default) — show detected software and recommended extensions
|
|
8
|
+
- `detect catalog` — show full detection catalog
|
|
9
|
+
- `detect missing` — list extensions that should be installed
|
|
10
|
+
- `--install` flag to install missing extensions after scan
|
|
11
|
+
- `--json` output mode
|
|
12
|
+
- `legionio update` now suggests new extensions via lex-detect after updating gems
|
|
13
|
+
|
|
3
14
|
## [1.4.66] - 2026-03-18
|
|
4
15
|
|
|
5
16
|
### Fixed
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
require 'legion/cli/output'
|
|
5
|
+
|
|
6
|
+
module Legion
|
|
7
|
+
module CLI
|
|
8
|
+
class Detect < Thor
|
|
9
|
+
namespace 'detect'
|
|
10
|
+
|
|
11
|
+
def self.exit_on_failure?
|
|
12
|
+
true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class_option :json, type: :boolean, default: false, desc: 'Output as JSON'
|
|
16
|
+
class_option :no_color, type: :boolean, default: false, desc: 'Disable color output'
|
|
17
|
+
|
|
18
|
+
default_task :scan
|
|
19
|
+
|
|
20
|
+
desc 'scan', 'Scan environment and recommend extensions (default)'
|
|
21
|
+
option :install, type: :boolean, default: false, desc: 'Install missing extensions after scan'
|
|
22
|
+
option :dry_run, type: :boolean, default: false, desc: 'Show what would be installed without installing'
|
|
23
|
+
def scan
|
|
24
|
+
out = formatter
|
|
25
|
+
require_detect_gem
|
|
26
|
+
|
|
27
|
+
results = Legion::Extensions::Detect.scan
|
|
28
|
+
|
|
29
|
+
if options[:json]
|
|
30
|
+
out.json(detections: results)
|
|
31
|
+
else
|
|
32
|
+
display_detections(out, results)
|
|
33
|
+
install_missing(out) if options[:install]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc 'catalog', 'Show the full detection catalog'
|
|
38
|
+
def catalog
|
|
39
|
+
out = formatter
|
|
40
|
+
require_detect_gem
|
|
41
|
+
|
|
42
|
+
catalog = Legion::Extensions::Detect.catalog
|
|
43
|
+
|
|
44
|
+
if options[:json]
|
|
45
|
+
catalog_data = catalog.map do |rule|
|
|
46
|
+
{ name: rule[:name], extensions: rule[:extensions],
|
|
47
|
+
signals: rule[:signals].map { |s| "#{s[:type]}:#{s[:match]}" } }
|
|
48
|
+
end
|
|
49
|
+
out.json(catalog: catalog_data)
|
|
50
|
+
else
|
|
51
|
+
out.header('Detection Catalog')
|
|
52
|
+
out.spacer
|
|
53
|
+
catalog.each do |rule|
|
|
54
|
+
signals = rule[:signals].map { |s| "#{s[:type]}:#{s[:match]}" }.join(', ')
|
|
55
|
+
extensions = rule[:extensions].join(', ')
|
|
56
|
+
puts " #{out.colorize(rule[:name].ljust(20), :label)} #{extensions.ljust(30)} #{signals}"
|
|
57
|
+
end
|
|
58
|
+
out.spacer
|
|
59
|
+
puts " #{catalog.size} detection rules"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc 'missing', 'List extensions that should be installed but are not'
|
|
64
|
+
def missing
|
|
65
|
+
out = formatter
|
|
66
|
+
require_detect_gem
|
|
67
|
+
|
|
68
|
+
missing_gems = Legion::Extensions::Detect.missing
|
|
69
|
+
|
|
70
|
+
if options[:json]
|
|
71
|
+
out.json(missing: missing_gems)
|
|
72
|
+
elsif missing_gems.empty?
|
|
73
|
+
out.success('All detected extensions are installed')
|
|
74
|
+
else
|
|
75
|
+
out.header('Missing Extensions')
|
|
76
|
+
missing_gems.each { |name| puts " gem install #{name}" }
|
|
77
|
+
out.spacer
|
|
78
|
+
puts " #{missing_gems.size} extension(s) recommended"
|
|
79
|
+
puts " Run 'legionio detect --install' to install them"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
no_commands do
|
|
84
|
+
def formatter
|
|
85
|
+
@formatter ||= Output::Formatter.new(
|
|
86
|
+
json: options[:json],
|
|
87
|
+
color: !options[:no_color]
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def require_detect_gem
|
|
94
|
+
require 'legion/extensions/detect'
|
|
95
|
+
rescue LoadError => e
|
|
96
|
+
formatter.error("lex-detect gem not installed: #{e.message}")
|
|
97
|
+
puts ' Install with: gem install lex-detect'
|
|
98
|
+
raise SystemExit, 1
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def display_detections(out, results)
|
|
102
|
+
if results.empty?
|
|
103
|
+
out.detail('No software detected that maps to Legion extensions.')
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
out.header('Environment Detection')
|
|
108
|
+
out.spacer
|
|
109
|
+
|
|
110
|
+
installed_count = 0
|
|
111
|
+
total_count = 0
|
|
112
|
+
|
|
113
|
+
results.each do |detection|
|
|
114
|
+
signals = detection[:matched_signals].join(', ')
|
|
115
|
+
detection[:extensions].each do |ext|
|
|
116
|
+
total_count += 1
|
|
117
|
+
is_installed = detection[:installed][ext]
|
|
118
|
+
installed_count += 1 if is_installed
|
|
119
|
+
status = is_installed ? out.colorize('installed', :success) : out.colorize('missing', :error)
|
|
120
|
+
puts " #{out.colorize(detection[:name].ljust(20), :label)} #{signals.ljust(35)} #{ext.ljust(25)} #{status}"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
out.spacer
|
|
125
|
+
puts " #{installed_count} of #{total_count} extension(s) installed"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def install_missing(out)
|
|
129
|
+
missing_gems = Legion::Extensions::Detect.missing
|
|
130
|
+
return if missing_gems.empty?
|
|
131
|
+
|
|
132
|
+
out.spacer
|
|
133
|
+
if options[:dry_run]
|
|
134
|
+
out.header('Would install')
|
|
135
|
+
missing_gems.each { |name| puts " #{name}" }
|
|
136
|
+
return
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
out.header('Installing missing extensions')
|
|
140
|
+
result = Legion::Extensions::Detect.install_missing!
|
|
141
|
+
|
|
142
|
+
result[:installed].each { |name| out.success(" Installed #{name}") }
|
|
143
|
+
result[:failed].each { |f| out.error(" Failed: #{f[:name]} — #{f[:error]}") }
|
|
144
|
+
|
|
145
|
+
out.spacer
|
|
146
|
+
if result[:failed].empty?
|
|
147
|
+
out.success("#{result[:installed].size} extension(s) installed")
|
|
148
|
+
else
|
|
149
|
+
out.warn("#{result[:installed].size} installed, #{result[:failed].size} failed")
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -127,6 +127,21 @@ module Legion
|
|
|
127
127
|
puts 'All gems are up to date'
|
|
128
128
|
end
|
|
129
129
|
out.error("#{failed.size} gem(s) failed to update") if failed.any?
|
|
130
|
+
|
|
131
|
+
suggest_detect(out)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def suggest_detect(out)
|
|
135
|
+
require 'legion/extensions/detect'
|
|
136
|
+
missing = Legion::Extensions::Detect.missing
|
|
137
|
+
return if missing.empty?
|
|
138
|
+
|
|
139
|
+
out.spacer
|
|
140
|
+
puts " #{missing.size} new extension(s) recommended based on your environment:"
|
|
141
|
+
missing.each { |name| puts " gem install #{name}" }
|
|
142
|
+
puts " Run 'legionio detect --install' to install them"
|
|
143
|
+
rescue LoadError
|
|
144
|
+
nil
|
|
130
145
|
end
|
|
131
146
|
end
|
|
132
147
|
end
|
data/lib/legion/cli.rb
CHANGED
|
@@ -35,6 +35,7 @@ module Legion
|
|
|
35
35
|
autoload :Auth, 'legion/cli/auth_command'
|
|
36
36
|
autoload :Rbac, 'legion/cli/rbac_command'
|
|
37
37
|
autoload :Audit, 'legion/cli/audit_command'
|
|
38
|
+
autoload :Detect, 'legion/cli/detect_command'
|
|
38
39
|
autoload :Update, 'legion/cli/update_command'
|
|
39
40
|
autoload :Init, 'legion/cli/init_command'
|
|
40
41
|
autoload :Skill, 'legion/cli/skill_command'
|
|
@@ -211,6 +212,9 @@ module Legion
|
|
|
211
212
|
desc 'audit SUBCOMMAND', 'Audit log inspection and verification'
|
|
212
213
|
subcommand 'audit', Legion::CLI::Audit
|
|
213
214
|
|
|
215
|
+
desc 'detect', 'Scan environment and recommend extensions'
|
|
216
|
+
subcommand 'detect', Legion::CLI::Detect
|
|
217
|
+
|
|
214
218
|
desc 'update', 'Update Legion gems to latest versions'
|
|
215
219
|
subcommand 'update', Legion::CLI::Update
|
|
216
220
|
|
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.67
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -430,6 +430,7 @@ files:
|
|
|
430
430
|
- lib/legion/cli/dashboard/data_fetcher.rb
|
|
431
431
|
- lib/legion/cli/dashboard/renderer.rb
|
|
432
432
|
- lib/legion/cli/dashboard_command.rb
|
|
433
|
+
- lib/legion/cli/detect_command.rb
|
|
433
434
|
- lib/legion/cli/doctor/bundle_check.rb
|
|
434
435
|
- lib/legion/cli/doctor/cache_check.rb
|
|
435
436
|
- lib/legion/cli/doctor/config_check.rb
|