legionio 1.4.116 → 1.4.117

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6979926154eb319a990087443af9becaa5831d4eb0ab5525f1b044287e2c279f
4
- data.tar.gz: '0129c7452e19e2f9c63f996ea254b44764a6caebfccb84f50ad0c8d058b910bb'
3
+ metadata.gz: d03cb4a8c6be7dd7d726f3999ebf88826914163aa9c59ac3a7206f7975616892
4
+ data.tar.gz: 1002f6425389c201d397f07163ccc40101880d0f9dadce0fb4c4159078b531cb
5
5
  SHA512:
6
- metadata.gz: c1d1b49e93559deda93761855fa70fb72fe76673af87cf7c5fa4819a326d57318a2cc43c7c1f8bf9d0311487e3bbe1ee9d2154f52f14254630f4db8d7302f23f
7
- data.tar.gz: fec26b4465b3806815ca5ddc62a476a54c4e88ce94654a18983aadab6940fcca9197ee8545b85038960d9688a9ba64d810499eef09374d0723081e523048766c
6
+ metadata.gz: 3f1679456170344d1ea966e7b08f5ba518f2f1957030b1cfa18c614516502bab2848861fd2c698f86ef72889cf4f79882ee1cafbf65a4bf8f3b00b23e8fb517c
7
+ data.tar.gz: 72c3d056636a57c41244a9483824d6eaa448feb3b970bff31dc79741ba884e89045d4cec22b32e716d350bdbbd72b67465d09ca91aade426c8b9596f7fb12e92
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Legion Changelog
2
2
 
3
+ ## [1.4.117] - 2026-03-22
4
+
5
+ ### Added
6
+ - `Legion::CLI::Error` gains `suggestions`, `code` attributes and `.actionable` factory method
7
+ - `Legion::CLI::ErrorHandler` module: 6-pattern matcher maps common exceptions (RabbitMQ, DB, extensions, permissions, data, Vault) to actionable errors with fix suggestions
8
+ - `ErrorHandler.wrap` wraps any `StandardError` into a `CLI::Error` with suggestions when a pattern matches
9
+ - `ErrorHandler.format_error` prints suggestions below the error line when the error is actionable
10
+ - `Legion::CLI::Main.start` overrides Thor's entry point to wrap unhandled exceptions through `ErrorHandler` before exiting
11
+
3
12
  ## [1.4.116] - 2026-03-22
4
13
 
5
14
  ### Added
@@ -2,6 +2,19 @@
2
2
 
3
3
  module Legion
4
4
  module CLI
5
- class Error < StandardError; end
5
+ class Error < StandardError
6
+ attr_reader :suggestions, :code
7
+
8
+ def self.actionable(code:, message:, suggestions: [])
9
+ err = new(message)
10
+ err.instance_variable_set(:@code, code)
11
+ err.instance_variable_set(:@suggestions, suggestions)
12
+ err
13
+ end
14
+
15
+ def actionable?
16
+ !suggestions.nil? && !suggestions.empty?
17
+ end
18
+ end
6
19
  end
7
20
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module CLI
5
+ module ErrorHandler
6
+ PATTERNS = [
7
+ {
8
+ match: /connection refused.*5672|ECONNREFUSED.*5672|bunny.*not connected/i,
9
+ code: :transport_unavailable,
10
+ message: 'Cannot connect to RabbitMQ',
11
+ suggestions: [
12
+ "Run 'legion doctor' to diagnose connectivity",
13
+ "Check transport settings: 'legion config show -s transport'",
14
+ 'Verify RabbitMQ is running: brew services list | grep rabbitmq'
15
+ ]
16
+ },
17
+ {
18
+ match: /table.*not.*found|no such table|PG::UndefinedTable|Sequel::DatabaseError.*exist/i,
19
+ code: :database_missing,
20
+ message: 'Database table not found',
21
+ suggestions: [
22
+ "Run 'legion start' to apply pending migrations",
23
+ "Check database config: 'legion config show -s data'",
24
+ "Verify database is running: 'legion doctor'"
25
+ ]
26
+ },
27
+ {
28
+ match: /extension.*not.*found|no such extension|uninitialized constant.*Extensions/i,
29
+ code: :extension_missing,
30
+ message: 'Extension not found',
31
+ suggestions: [
32
+ "Search available extensions: 'legion marketplace search <name>'",
33
+ 'Install with: gem install lex-<name>',
34
+ "List installed: 'legion lex list'"
35
+ ]
36
+ },
37
+ {
38
+ match: /permission denied|EACCES/i,
39
+ code: :permission_denied,
40
+ message: 'Permission denied',
41
+ suggestions: [
42
+ 'Try running with sudo for system directories',
43
+ 'Set custom config dir: LEGIONIO_CONFIG_DIR=~/.legionio',
44
+ 'Check file permissions: ls -la ~/.legionio/'
45
+ ]
46
+ },
47
+ {
48
+ match: /legion-data.*not.*connected|data.*not.*available/i,
49
+ code: :data_unavailable,
50
+ message: 'Database not connected',
51
+ suggestions: [
52
+ "Check database config: 'legion config show -s data'",
53
+ "Run diagnostics: 'legion doctor'",
54
+ 'Some commands work without a database — try adding --no-data flag'
55
+ ]
56
+ },
57
+ {
58
+ match: /vault.*not.*connected|vault.*sealed|VAULT_ADDR/i,
59
+ code: :vault_unavailable,
60
+ message: 'Vault not connected',
61
+ suggestions: [
62
+ "Check Vault config: 'legion config show -s crypt'",
63
+ 'Verify VAULT_ADDR and VAULT_TOKEN environment variables',
64
+ "Run diagnostics: 'legion doctor'"
65
+ ]
66
+ }
67
+ ].freeze
68
+
69
+ module_function
70
+
71
+ def wrap(error)
72
+ pattern = PATTERNS.find { |p| error.message.match?(p[:match]) }
73
+ return error unless pattern
74
+
75
+ Error.actionable(
76
+ code: pattern[:code],
77
+ message: "#{pattern[:message]}: #{error.message}",
78
+ suggestions: pattern[:suggestions]
79
+ )
80
+ end
81
+
82
+ def format_error(error, formatter)
83
+ formatter.error(error.message)
84
+ return unless error.is_a?(Error) && error.actionable?
85
+
86
+ error.suggestions.each do |suggestion|
87
+ puts " #{formatter.colorize('>', :label)} #{suggestion}"
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
data/lib/legion/cli.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'thor'
4
4
  require 'legion/version'
5
5
  require 'legion/cli/error'
6
+ require 'legion/cli/error_handler'
6
7
  require 'legion/cli/output'
7
8
  require 'legion/cli/connection'
8
9
 
@@ -61,6 +62,19 @@ module Legion
61
62
  true
62
63
  end
63
64
 
65
+ def self.start(given_args = ARGV, config = {})
66
+ super
67
+ rescue Legion::CLI::Error => e
68
+ formatter = Output::Formatter.new(json: given_args.include?('--json'), color: !given_args.include?('--no-color'))
69
+ ErrorHandler.format_error(e, formatter)
70
+ exit(1)
71
+ rescue StandardError => e
72
+ wrapped = ErrorHandler.wrap(e)
73
+ formatter = Output::Formatter.new(json: given_args.include?('--json'), color: !given_args.include?('--no-color'))
74
+ ErrorHandler.format_error(wrapped, formatter)
75
+ exit(1)
76
+ end
77
+
64
78
  class_option :json, type: :boolean, default: false, desc: 'Output as JSON'
65
79
  class_option :no_color, type: :boolean, default: false, desc: 'Disable color output'
66
80
  class_option :verbose, type: :boolean, default: false, aliases: ['-V'], desc: 'Verbose logging'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.4.116'
4
+ VERSION = '1.4.117'
5
5
  end
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.116
4
+ version: 1.4.117
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -498,6 +498,7 @@ files:
498
498
  - lib/legion/cli/doctor/vault_check.rb
499
499
  - lib/legion/cli/doctor_command.rb
500
500
  - lib/legion/cli/error.rb
501
+ - lib/legion/cli/error_handler.rb
501
502
  - lib/legion/cli/eval_command.rb
502
503
  - lib/legion/cli/failover_command.rb
503
504
  - lib/legion/cli/function.rb