ukiryu 0.1.1 → 0.1.3

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +58 -14
  3. data/.gitignore +3 -0
  4. data/.rubocop_todo.yml +170 -79
  5. data/Gemfile +1 -1
  6. data/README.adoc +1603 -576
  7. data/docs/.gitignore +1 -0
  8. data/docs/Gemfile +10 -0
  9. data/docs/INDEX.adoc +261 -0
  10. data/docs/_config.yml +180 -0
  11. data/docs/advanced/custom-tool-classes.adoc +581 -0
  12. data/docs/advanced/index.adoc +20 -0
  13. data/docs/features/configuration.adoc +657 -0
  14. data/docs/features/index.adoc +31 -0
  15. data/docs/features/platform-support.adoc +488 -0
  16. data/docs/getting-started/core-concepts.adoc +666 -0
  17. data/docs/getting-started/index.adoc +36 -0
  18. data/docs/getting-started/installation.adoc +216 -0
  19. data/docs/getting-started/quick-start.adoc +258 -0
  20. data/docs/guides/env-var-sets.adoc +388 -0
  21. data/docs/guides/index.adoc +20 -0
  22. data/docs/interfaces/cli.adoc +609 -0
  23. data/docs/interfaces/index.adoc +153 -0
  24. data/docs/interfaces/ruby-api.adoc +538 -0
  25. data/docs/lychee.toml +49 -0
  26. data/docs/reference/configuration-options.adoc +720 -0
  27. data/docs/reference/error-codes.adoc +634 -0
  28. data/docs/reference/index.adoc +20 -0
  29. data/docs/reference/ruby-api.adoc +1217 -0
  30. data/docs/understanding/index.adoc +20 -0
  31. data/lib/ukiryu/cli.rb +43 -58
  32. data/lib/ukiryu/cli_commands/base_command.rb +16 -27
  33. data/lib/ukiryu/cli_commands/cache_command.rb +100 -0
  34. data/lib/ukiryu/cli_commands/commands_command.rb +8 -8
  35. data/lib/ukiryu/cli_commands/commands_command.rb.fixed +1 -1
  36. data/lib/ukiryu/cli_commands/config_command.rb +49 -7
  37. data/lib/ukiryu/cli_commands/definitions_command.rb +254 -0
  38. data/lib/ukiryu/cli_commands/describe_command.rb +13 -7
  39. data/lib/ukiryu/cli_commands/describe_command.rb.fixed +1 -1
  40. data/lib/ukiryu/cli_commands/docs_command.rb +148 -0
  41. data/lib/ukiryu/cli_commands/exec_inline_command.rb.fixed +1 -1
  42. data/lib/ukiryu/cli_commands/extract_command.rb +2 -2
  43. data/lib/ukiryu/cli_commands/info_command.rb +7 -7
  44. data/lib/ukiryu/cli_commands/lint_command.rb +167 -0
  45. data/lib/ukiryu/cli_commands/list_command.rb +6 -6
  46. data/lib/ukiryu/cli_commands/opts_command.rb +2 -2
  47. data/lib/ukiryu/cli_commands/opts_command.rb.fixed +1 -1
  48. data/lib/ukiryu/cli_commands/register_command.rb +144 -0
  49. data/lib/ukiryu/cli_commands/resolve_command.rb +124 -0
  50. data/lib/ukiryu/cli_commands/run_command.rb +38 -14
  51. data/lib/ukiryu/cli_commands/run_file_command.rb +2 -2
  52. data/lib/ukiryu/cli_commands/system_command.rb +50 -32
  53. data/lib/ukiryu/cli_commands/validate_command.rb +452 -51
  54. data/lib/ukiryu/cli_commands/which_command.rb +5 -5
  55. data/lib/ukiryu/command_builder.rb +81 -23
  56. data/lib/ukiryu/config/env_provider.rb +3 -3
  57. data/lib/ukiryu/config/env_schema.rb +6 -6
  58. data/lib/ukiryu/config.rb +11 -11
  59. data/lib/ukiryu/definition/definition_cache.rb +238 -0
  60. data/lib/ukiryu/definition/definition_composer.rb +257 -0
  61. data/lib/ukiryu/definition/definition_linter.rb +460 -0
  62. data/lib/ukiryu/definition/definition_validator.rb +320 -0
  63. data/lib/ukiryu/definition/discovery.rb +239 -0
  64. data/lib/ukiryu/definition/documentation_generator.rb +429 -0
  65. data/lib/ukiryu/definition/lint_issue.rb +168 -0
  66. data/lib/ukiryu/definition/loader.rb +139 -0
  67. data/lib/ukiryu/definition/metadata.rb +159 -0
  68. data/lib/ukiryu/definition/source.rb +87 -0
  69. data/lib/ukiryu/definition/sources/file.rb +138 -0
  70. data/lib/ukiryu/definition/sources/string.rb +88 -0
  71. data/lib/ukiryu/definition/validation_result.rb +158 -0
  72. data/lib/ukiryu/definition/version_resolver.rb +194 -0
  73. data/lib/ukiryu/definition.rb +40 -0
  74. data/lib/ukiryu/errors.rb +6 -0
  75. data/lib/ukiryu/execution_context.rb +11 -11
  76. data/lib/ukiryu/executor.rb +6 -0
  77. data/lib/ukiryu/extractors/extractor.rb +6 -5
  78. data/lib/ukiryu/extractors/help_parser.rb +13 -19
  79. data/lib/ukiryu/logger.rb +3 -1
  80. data/lib/ukiryu/models/command_definition.rb +3 -3
  81. data/lib/ukiryu/models/command_info.rb +1 -1
  82. data/lib/ukiryu/models/components.rb +1 -3
  83. data/lib/ukiryu/models/env_var_definition.rb +11 -3
  84. data/lib/ukiryu/models/flag_definition.rb +15 -0
  85. data/lib/ukiryu/models/option_definition.rb +7 -7
  86. data/lib/ukiryu/models/platform_profile.rb +6 -3
  87. data/lib/ukiryu/models/routing.rb +1 -1
  88. data/lib/ukiryu/models/tool_definition.rb +2 -4
  89. data/lib/ukiryu/models/tool_metadata.rb +6 -6
  90. data/lib/ukiryu/models/validation_result.rb +1 -1
  91. data/lib/ukiryu/models/version_compatibility.rb +6 -3
  92. data/lib/ukiryu/models/version_detection.rb +10 -1
  93. data/lib/ukiryu/{registry.rb → register.rb} +54 -38
  94. data/lib/ukiryu/register_auto_manager.rb +268 -0
  95. data/lib/ukiryu/schema_validator.rb +31 -10
  96. data/lib/ukiryu/shell/base.rb +18 -0
  97. data/lib/ukiryu/shell/bash.rb +19 -1
  98. data/lib/ukiryu/shell/cmd.rb +11 -1
  99. data/lib/ukiryu/shell/powershell.rb +11 -1
  100. data/lib/ukiryu/shell.rb +1 -1
  101. data/lib/ukiryu/tool.rb +107 -95
  102. data/lib/ukiryu/tool_index.rb +22 -22
  103. data/lib/ukiryu/tools/base.rb +12 -25
  104. data/lib/ukiryu/tools/generator.rb +7 -7
  105. data/lib/ukiryu/tools.rb +3 -3
  106. data/lib/ukiryu/type.rb +20 -5
  107. data/lib/ukiryu/version.rb +1 -1
  108. data/lib/ukiryu/version_detector.rb +21 -2
  109. data/lib/ukiryu.rb +6 -3
  110. data/ukiryu-proposal.md +41 -41
  111. data/ukiryu.gemspec +1 -0
  112. metadata +64 -8
  113. data/.gitmodules +0 -3
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ukiryu
4
+ module Definition
5
+ # Result of a definition validation
6
+ #
7
+ # This class represents the result of validating a tool definition
8
+ # against a JSON Schema or other validation rules.
9
+ class ValidationResult
10
+ attr_reader :errors, :warnings, :schema_path
11
+
12
+ def initialize(valid:, errors: [], warnings: [], schema_path: nil)
13
+ @valid = valid
14
+ @errors = errors
15
+ @warnings = warnings
16
+ @schema_path = schema_path
17
+ end
18
+
19
+ # Check if validation passed
20
+ #
21
+ # @return [Boolean] true if validation passed
22
+ def valid?
23
+ @valid
24
+ end
25
+
26
+ # Check if validation failed
27
+ #
28
+ # @return [Boolean] true if validation failed
29
+ def invalid?
30
+ !@valid
31
+ end
32
+
33
+ # Check if there are any errors
34
+ #
35
+ # @return [Boolean] true if there are errors
36
+ def has_errors?
37
+ !@errors.empty?
38
+ end
39
+
40
+ # Check if there are any warnings
41
+ #
42
+ # @return [Boolean] true if there are warnings
43
+ def has_warnings?
44
+ !@warnings.empty?
45
+ end
46
+
47
+ # Get total issue count
48
+ #
49
+ # @return [Integer] total number of issues (errors + warnings)
50
+ def issue_count
51
+ @errors.length + @warnings.length
52
+ end
53
+
54
+ # Get error count
55
+ #
56
+ # @return [Integer] number of errors
57
+ def error_count
58
+ @errors.length
59
+ end
60
+
61
+ # Get warning count
62
+ #
63
+ # @return [Integer] number of warnings
64
+ def warning_count
65
+ @warnings.length
66
+ end
67
+
68
+ # Create a successful validation result
69
+ #
70
+ # @return [ValidationResult] a successful result
71
+ def self.success
72
+ new(valid: true)
73
+ end
74
+
75
+ # Create a failed validation result
76
+ #
77
+ # @param errors [Array<String>] validation errors
78
+ # @param warnings [Array<String>] validation warnings
79
+ # @return [ValidationResult] a failed result
80
+ def self.failure(errors, warnings = [])
81
+ new(valid: false, errors: errors, warnings: warnings)
82
+ end
83
+
84
+ # Create a result with warnings
85
+ #
86
+ # @param warnings [Array<String>] validation warnings
87
+ # @return [ValidationResult] a result with warnings
88
+ def self.with_warnings(warnings)
89
+ new(valid: true, warnings: warnings)
90
+ end
91
+
92
+ # Convert to hash
93
+ #
94
+ # @return [Hash] hash representation
95
+ def to_h
96
+ {
97
+ valid: @valid,
98
+ errors: @errors,
99
+ warnings: @warnings,
100
+ schema_path: @schema_path,
101
+ error_count: error_count,
102
+ warning_count: warning_count
103
+ }
104
+ end
105
+
106
+ # Convert to JSON
107
+ #
108
+ # @return [String] JSON representation
109
+ def to_json(*args)
110
+ require 'json'
111
+ to_h.to_json(*args)
112
+ end
113
+
114
+ # Human-readable summary
115
+ #
116
+ # @return [String] summary text
117
+ def summary
118
+ if valid?
119
+ if has_warnings?
120
+ "Valid with #{warning_count} warning(s)"
121
+ else
122
+ 'Valid'
123
+ end
124
+ else
125
+ msg = "Invalid (#{error_count} error(s)"
126
+ msg += ", #{warning_count} warning(s)" if has_warnings?
127
+ "#{msg})"
128
+ end
129
+ end
130
+
131
+ # Detailed message string
132
+ #
133
+ # @return [String] detailed message
134
+ def to_s
135
+ output = []
136
+ output << "Validation: #{summary}"
137
+
138
+ if has_errors?
139
+ output << ''
140
+ output << 'Errors:'
141
+ @errors.each_with_index do |error, i|
142
+ output << " #{i + 1}. #{error}"
143
+ end
144
+ end
145
+
146
+ if has_warnings?
147
+ output << ''
148
+ output << 'Warnings:'
149
+ @warnings.each_with_index do |warning, i|
150
+ output << " #{i + 1}. #{warning}"
151
+ end
152
+ end
153
+
154
+ output.join("\n")
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ukiryu
4
+ module Definition
5
+ # Resolve semantic version constraints
6
+ #
7
+ # This class handles semantic versioning constraints like:
8
+ # - "1.0" - exact version
9
+ # - ">= 1.0" - minimum version (inclusive)
10
+ # - "~> 1.2" - pessimistic version constraint
11
+ class VersionResolver
12
+ # Version constraint structure
13
+ class Constraint
14
+ attr_reader :operator, :version, :raw
15
+
16
+ def initialize(operator, version, raw = nil)
17
+ @operator = operator
18
+ @version = version
19
+ @raw = raw || "#{operator} #{version}"
20
+ end
21
+
22
+ # Exact version constraint
23
+ def self.exact(version)
24
+ new(:==, version, version)
25
+ end
26
+
27
+ # Minimum version constraint (inclusive)
28
+ def self.min(version)
29
+ new(:>=, version)
30
+ end
31
+
32
+ # Maximum version constraint (inclusive)
33
+ def self.max(version)
34
+ new(:<=, version)
35
+ end
36
+
37
+ # Pessimistic version constraint
38
+ def self.pessimistic(version)
39
+ new('~>'.to_sym, version)
40
+ end
41
+
42
+ # Range constraint
43
+ def self.range(min_version, max_version)
44
+ # This is represented as two constraints internally
45
+ [new(:>=, min_version), new(:<, max_version)]
46
+ end
47
+
48
+ def to_s
49
+ @raw
50
+ end
51
+ end
52
+
53
+ # Parse a version constraint string
54
+ #
55
+ # @param constraint_string [String] the constraint string
56
+ # @return [Array<Constraint>] array of constraints
57
+ def self.parse_constraint(constraint_string)
58
+ return [Constraint.exact(constraint_string)] unless constraint_string.match?(/[<>=~]/)
59
+
60
+ constraints = []
61
+
62
+ # Split by comma for compound constraints
63
+ constraint_string.split(',').map(&:strip).each do |part|
64
+ case part
65
+ when /\A~>(?:\s*(.+))?/ # Updated regex for ~> operator
66
+ # Pessimistic version constraint
67
+ version = ::Regexp.last_match(1) || ''
68
+ constraints << Constraint.pessimistic(version.strip)
69
+ when /\A>=\s*(.+)/
70
+ # Minimum version (inclusive)
71
+ constraints << Constraint.min(::Regexp.last_match(1))
72
+ when /\A>\s*(.+)/
73
+ # Minimum version (exclusive)
74
+ constraints << Constraint.new(:>, ::Regexp.last_match(1))
75
+ when /\A<=\s*(.+)/
76
+ # Maximum version (inclusive)
77
+ constraints << Constraint.max(::Regexp.last_match(1))
78
+ when /\A<\s*(.+)/
79
+ # Maximum version (exclusive)
80
+ constraints << Constraint.new(:<, ::Regexp.last_match(1))
81
+ when /\A==\s*(.+)/
82
+ # Exact version
83
+ constraints << Constraint.exact(::Regexp.last_match(1))
84
+ else
85
+ # Assume exact version
86
+ constraints << Constraint.exact(part.strip)
87
+ end
88
+ end
89
+
90
+ constraints
91
+ end
92
+
93
+ # Check if a version satisfies a constraint
94
+ #
95
+ # @param version [String] the version to check
96
+ # @param constraint [String, Array<Constraint>] the constraint(s)
97
+ # @return [Boolean] true if version satisfies constraint
98
+ def self.satisfies?(version, constraint)
99
+ constraints = constraint.is_a?(Array) ? constraint : parse_constraint(constraint)
100
+
101
+ v_parts = parse_version(version)
102
+
103
+ constraints.all? do |c|
104
+ case c.operator
105
+ when :==
106
+ v_parts == parse_version(c.version)
107
+ when :>=
108
+ compare_versions(v_parts, parse_version(c.version)) >= 0
109
+ when :>
110
+ compare_versions(v_parts, parse_version(c.version)).positive?
111
+ when :<=
112
+ compare_versions(v_parts, parse_version(c.version)) <= 0
113
+ when :<
114
+ compare_versions(v_parts, parse_version(c.version)).negative?
115
+ when '~>'.to_sym
116
+ # Pessimistic version constraint: >= x.y.z, < x.(y+1).0
117
+ base = parse_version(c.version)
118
+ upper = base[0...-1] + [base[-1] + 1, 0]
119
+ compare_versions(v_parts, base) >= 0 && compare_versions(v_parts, upper).negative?
120
+ else
121
+ false
122
+ end
123
+ end
124
+ end
125
+
126
+ # Resolve the best matching version from available versions
127
+ #
128
+ # @param constraint [String] the version constraint
129
+ # @param available_versions [Array<String>] available versions
130
+ # @return [String, nil] best matching version, or nil if none match
131
+ def self.resolve(constraint, available_versions)
132
+ return nil if available_versions.nil? || available_versions.empty?
133
+
134
+ # Parse constraint
135
+ constraints = parse_constraint(constraint)
136
+
137
+ # Filter versions that satisfy the constraint
138
+ matching = available_versions.select { |v| satisfies?(v, constraints) }
139
+
140
+ # Return highest matching version
141
+ matching.max_by { |v| parse_version(v) }
142
+ end
143
+
144
+ # Compare two version strings
145
+ #
146
+ # @param v1 [String, Array] first version or parts
147
+ # @param v2 [String, Array] second version or parts
148
+ # @return [Integer] comparison result (-1, 0, 1)
149
+ def self.compare_versions(v1, v2)
150
+ parts1 = v1.is_a?(Array) ? v1 : parse_version(v1)
151
+ parts2 = v2.is_a?(Array) ? v2 : parse_version(v2)
152
+
153
+ max_length = [parts1.length, parts2.length].max
154
+ max_length.times do |i|
155
+ p1 = parts1[i] || 0
156
+ p2 = parts2[i] || 0
157
+ comparison = p1 <=> p2
158
+ return comparison unless comparison.zero?
159
+ end
160
+
161
+ 0
162
+ end
163
+
164
+ # Parse a version string into components
165
+ #
166
+ # @param version_string [String] the version string
167
+ # @return [Array<Integer>] version components
168
+ def self.parse_version(version_string)
169
+ version_string.to_s.split('.').map(&:to_i)
170
+ end
171
+
172
+ # Get the latest version from a list
173
+ #
174
+ # @param versions [Array<String>] list of versions
175
+ # @return [String, nil] the latest version
176
+ def self.latest(versions)
177
+ return nil if versions.nil? || versions.empty?
178
+
179
+ versions.max_by { |v| parse_version(v) }
180
+ end
181
+
182
+ # Get the compatible version range for a pessimistic constraint
183
+ #
184
+ # @param version [String] the base version
185
+ # @return [Array<String>] [min_version, max_version]
186
+ def self.pessimistic_range(version)
187
+ parts = parse_version(version)
188
+ min = version
189
+ max = "#{parts[0...-1].join('.')}.#{parts[-1] + 1}"
190
+ [min, max]
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'definition/source'
4
+ require_relative 'definition/sources/file'
5
+ require_relative 'definition/sources/string'
6
+
7
+ # Export classes for convenience
8
+ Ukiryu::Definition::FileSource = Ukiryu::Definition::Sources::FileSource
9
+ Ukiryu::Definition::StringSource = Ukiryu::Definition::Sources::StringSource
10
+
11
+ require_relative 'definition/loader'
12
+ require_relative 'definition/metadata'
13
+ require_relative 'definition/discovery'
14
+ require_relative 'definition/version_resolver'
15
+ require_relative 'definition/definition_cache'
16
+ require_relative 'definition/definition_composer'
17
+
18
+ # Phase 5: Ecosystem - Validation, linting, documentation
19
+ require_relative 'definition/validation_result'
20
+ require_relative 'definition/definition_validator'
21
+ require_relative 'definition/lint_issue'
22
+ require_relative 'definition/definition_linter'
23
+ require_relative 'definition/documentation_generator'
24
+
25
+ module Ukiryu
26
+ # Definition loading module
27
+ #
28
+ # Provides functionality for loading tool definitions from various sources:
29
+ # - Files on the filesystem
30
+ # - YAML strings
31
+ # - XDG-compliant system paths
32
+ # - Tool-bundled locations
33
+ # - Central register (existing)
34
+ #
35
+ # @see Ukiryu::Tool::load
36
+ # @see Ukiryu::Tool::load_from_string
37
+ # @see Ukiryu::Definition::Discovery
38
+ module Definition
39
+ end
40
+ end
data/lib/ukiryu/errors.rb CHANGED
@@ -18,6 +18,12 @@ module Ukiryu
18
18
  class ProfileLoadError < Error; end
19
19
 
20
20
  # Definition loading errors
21
+ class DefinitionError < Error; end
22
+ class DefinitionNotFoundError < DefinitionError; end
23
+ class DefinitionLoadError < DefinitionError; end
24
+ class DefinitionValidationError < DefinitionError; end
25
+
26
+ # Definition loading errors (legacy, use DefinitionError instead)
21
27
  class LoadError < Error; end
22
28
 
23
29
  # Tool errors
@@ -32,13 +32,13 @@ module Ukiryu
32
32
  # context = Ukiryu::ExecutionContext.current
33
33
  # context.platform # => :macos
34
34
  # context.shell # => :bash
35
- # context.registry # => '/path/to/registry'
35
+ # context.register # => '/path/to/register'
36
36
  #
37
37
  # @example Using ExecutionContext in tests
38
38
  # context = Ukiryu::ExecutionContext.new(
39
39
  # platform: :linux,
40
40
  # shell: :zsh,
41
- # registry_path: '/test/registry'
41
+ # register_path: '/test/register'
42
42
  # )
43
43
  # context.platform # => :linux
44
44
  # context.shell # => :zsh
@@ -85,7 +85,7 @@ module Ukiryu
85
85
  new(
86
86
  platform: runtime.platform,
87
87
  shell: runtime.shell,
88
- registry_path: Registry.default_registry_path,
88
+ register_path: Register.default_register_path,
89
89
  timeout: Config.timeout,
90
90
  debug: Config.debug,
91
91
  metrics: Config.metrics
@@ -110,10 +110,10 @@ module Ukiryu
110
110
  # @return [Symbol] the shell
111
111
  attr_reader :shell
112
112
 
113
- # Registry path for tool profiles
113
+ # Register path for tool profiles
114
114
  #
115
- # @return [String, nil] the registry path
116
- attr_reader :registry_path
115
+ # @return [String, nil] the register path
116
+ attr_reader :register_path
117
117
 
118
118
  # Execution timeout in seconds
119
119
  #
@@ -139,21 +139,21 @@ module Ukiryu
139
139
  #
140
140
  # @param platform [Symbol] the platform (:macos, :linux, :windows)
141
141
  # @param shell [Symbol] the shell (:bash, :zsh, :fish, :powershell, :cmd)
142
- # @param registry_path [String, nil] the registry path
142
+ # @param register_path [String, nil] the register path
143
143
  # @param timeout [Integer, nil] execution timeout in seconds
144
144
  # @param debug [Boolean] debug mode flag
145
145
  # @param metrics [Boolean] metrics collection flag
146
146
  # @param options [Hash] additional options
147
147
  def initialize(platform: nil,
148
148
  shell: nil,
149
- registry_path: nil,
149
+ register_path: nil,
150
150
  timeout: nil,
151
151
  debug: false,
152
152
  metrics: false,
153
153
  options: {})
154
154
  @platform = platform
155
155
  @shell = shell
156
- @registry_path = registry_path
156
+ @register_path = register_path
157
157
  @timeout = timeout
158
158
  @debug = debug
159
159
  @metrics = metrics
@@ -226,7 +226,7 @@ module Ukiryu
226
226
  self.class.new(
227
227
  platform: changes.fetch(:platform, @platform),
228
228
  shell: changes.fetch(:shell, @shell),
229
- registry_path: changes.fetch(:registry_path, @registry_path),
229
+ register_path: changes.fetch(:register_path, @register_path),
230
230
  timeout: changes.fetch(:timeout, @timeout),
231
231
  debug: changes.fetch(:debug, @debug),
232
232
  metrics: changes.fetch(:metrics, @metrics),
@@ -238,7 +238,7 @@ module Ukiryu
238
238
  #
239
239
  # @return [String] the context as a string
240
240
  def to_s
241
- "ExecutionContext(platform=#{@platform}, shell=#{@shell}, registry=#{@registry_path})"
241
+ "ExecutionContext(platform=#{@platform}, shell=#{@shell}, register=#{@register_path})"
242
242
  end
243
243
 
244
244
  # Inspect
@@ -269,6 +269,12 @@ module Ukiryu
269
269
 
270
270
  # Add shell-specific headless environment
271
271
  headless = shell_instance.headless_environment
272
+
273
+ # For headless mode, explicitly remove DISPLAY
274
+ # If user_env explicitly didn't set DISPLAY, respect that (caller wants it removed)
275
+ # Otherwise, check if headless environment specifies DISPLAY
276
+ env.delete('DISPLAY') unless headless.key?('DISPLAY')
277
+
272
278
  env.merge!(headless)
273
279
 
274
280
  env
@@ -48,11 +48,12 @@ module Ukiryu
48
48
  def extract
49
49
  method = @options[:method] || :auto
50
50
 
51
- if method == :auto
51
+ case method
52
+ when :auto
52
53
  extract_auto
53
- elsif method == :native
54
+ when :native
54
55
  extract_with_native
55
- elsif method == :help
56
+ when :help
56
57
  extract_with_help
57
58
  else
58
59
  {
@@ -105,7 +106,7 @@ module Ukiryu
105
106
  else
106
107
  {
107
108
  success: false,
108
- error: "Native extraction failed",
109
+ error: 'Native extraction failed',
109
110
  method: :native,
110
111
  yaml: nil
111
112
  }
@@ -139,7 +140,7 @@ module Ukiryu
139
140
  else
140
141
  {
141
142
  success: false,
142
- error: "Help parsing failed",
143
+ error: 'Help parsing failed',
143
144
  method: :help,
144
145
  yaml: nil
145
146
  }
@@ -75,7 +75,7 @@ module Ukiryu
75
75
  #
76
76
  # @param help_text [String] the help output
77
77
  # @return [String] the tool name
78
- def extract_name(help_text)
78
+ def extract_name(_help_text)
79
79
  # Use the tool name passed to the extractor
80
80
  @tool_name.to_s
81
81
  end
@@ -88,9 +88,7 @@ module Ukiryu
88
88
  if version_result[:exit_status].zero?
89
89
  version_text = version_result[:stdout]
90
90
  # Try to extract version number
91
- if version_text =~ /(\d+\.\d+(?:\.\d+)?)/
92
- return Regexp.last_match(1)
93
- end
91
+ return Regexp.last_match(1) if version_text =~ /(\d+\.\d+(?:\.\d+)?)/
94
92
  end
95
93
  nil
96
94
  end
@@ -124,17 +122,13 @@ module Ukiryu
124
122
  'description' => line.strip
125
123
  }
126
124
 
127
- if short_opt
128
- option['cli'] = short_opt
129
- else
130
- option['cli'] = "--#{long_opt}"
131
- end
125
+ option['cli'] = (short_opt || "--#{long_opt}")
132
126
 
133
- if param
134
- option['type'] = infer_type(param)
135
- else
136
- option['type'] = 'boolean'
137
- end
127
+ option['type'] = if param
128
+ infer_type(param)
129
+ else
130
+ 'boolean'
131
+ end
138
132
 
139
133
  options << option
140
134
  elsif line =~ /^\s*\[--([a-z-]+)(?:[=\s]+([A-Z_]+))?\]/i
@@ -147,11 +141,11 @@ module Ukiryu
147
141
  'description' => line.strip
148
142
  }
149
143
 
150
- if param
151
- option['type'] = infer_type(param)
152
- else
153
- option['type'] = 'boolean'
154
- end
144
+ option['type'] = if param
145
+ infer_type(param)
146
+ else
147
+ 'boolean'
148
+ end
155
149
 
156
150
  options << option
157
151
  end
data/lib/ukiryu/logger.rb CHANGED
@@ -172,7 +172,9 @@ module Ukiryu
172
172
  if @paint_available
173
173
  paint = Paint.method(:[])
174
174
  @output.puts ''
175
- @output.puts "#{paint[' ✓', :green]} #{paint[selected_tool, :cyan, :bright]}#{paint[' implements: ', :white]}#{paint[identifier, :yellow]}"
175
+ @output.puts "#{paint[' ✓',
176
+ :green]} #{paint[selected_tool, :cyan,
177
+ :bright]}#{paint[' implements: ', :white]}#{paint[identifier, :yellow]}"
176
178
  else
177
179
  @output.puts ''
178
180
  @output.puts " ✓ #{selected_tool} implements: #{identifier}"
@@ -23,10 +23,10 @@ module Ukiryu
23
23
  attribute :description, :string
24
24
  attribute :usage, :string
25
25
  attribute :subcommand, :string
26
- attribute :execution_mode, :string
27
26
  attribute :belongs_to, :string # Parent command this action belongs to
28
27
  attribute :cli_flag, :string # CLI flag for this action (e.g., '-d' for delete)
29
28
  attribute :aliases, :string, collection: true, default: []
29
+ attribute :use_env_vars, :string, collection: true, default: []
30
30
 
31
31
  # Collections of model objects (lutaml-model handles serialization automatically)
32
32
  attribute :options, OptionDefinition, collection: true
@@ -34,7 +34,7 @@ module Ukiryu
34
34
  attribute :arguments, ArgumentDefinition, collection: true
35
35
  attribute :post_options, OptionDefinition, collection: true
36
36
  attribute :env_vars, EnvVarDefinition, collection: true
37
- attribute :exit_codes, ExitCodes # Exit code definitions for this command
37
+ attribute :exit_codes, ExitCodes # Exit code definitions for this command
38
38
 
39
39
  yaml do
40
40
  map_element 'name', to: :name
@@ -47,7 +47,7 @@ module Ukiryu
47
47
  map_element 'post_options', to: :post_options
48
48
  map_element 'env_vars', to: :env_vars
49
49
  map_element 'exit_codes', to: :exit_codes
50
- map_element 'execution_mode', to: :execution_mode
50
+ map_element 'use_env_vars', to: :use_env_vars
51
51
  map_element 'belongs_to', to: :belongs_to
52
52
  map_element 'cli_flag', to: :cli_flag
53
53
  map_element 'aliases', to: :aliases
@@ -12,7 +12,7 @@ module Ukiryu
12
12
  class CommandInfo < Lutaml::Model::Serializable
13
13
  attribute :executable, :string
14
14
  attribute :executable_name, :string
15
- attribute :tool_name, :string # Name of the tool being executed
15
+ attribute :tool_name, :string # Name of the tool being executed
16
16
  attribute :arguments, Arguments
17
17
  attribute :full_command, :string
18
18
  attribute :shell, :string
@@ -8,7 +8,7 @@ require_relative 'exit_codes'
8
8
 
9
9
  module Ukiryu
10
10
  module Models
11
- # Components registry for reusable definitions
11
+ # Components register for reusable definitions
12
12
  #
13
13
  # Enables sharing common option/argument/flag/exit_codes definitions
14
14
  # across commands through `$ref` references.
@@ -98,8 +98,6 @@ module Ukiryu
98
98
  argument(name)
99
99
  when 'exit_codes'
100
100
  @exit_codes
101
- else
102
- nil
103
101
  end
104
102
  end
105
103
  end