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,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative '../definition/definition_linter'
5
+
6
+ module Ukiryu
7
+ module CliCommands
8
+ # Lint tool definitions for best practices
9
+ #
10
+ # The lint command checks tool definitions for best practices,
11
+ # deprecated patterns, and potential issues.
12
+ class LintCommand < Thor
13
+ class_option :verbose, type: :boolean, default: false
14
+ class_option :format, type: :string, default: 'text', enum: %w[text json]
15
+ class_option :severity, type: :string, enum: %w[error warning info style], desc: 'Minimum severity level'
16
+
17
+ desc 'file PATH', 'Lint a definition file'
18
+ def file(path)
19
+ lint_file(path)
20
+ end
21
+
22
+ desc 'all', 'Lint all definitions in register'
23
+ option :register, type: :string, desc: 'Register path'
24
+ def all
25
+ lint_all
26
+ end
27
+
28
+ desc 'rules', 'List all linting rules'
29
+ def rules
30
+ list_rules
31
+ end
32
+
33
+ private
34
+
35
+ # Lint a single file
36
+ #
37
+ # @param path [String] file path
38
+ def lint_file(path)
39
+ result = Ukiryu::Definition::DefinitionLinter.lint_file(path)
40
+
41
+ output_result(result, path)
42
+
43
+ # Exit with error if there are errors
44
+ exit 1 if result.has_errors?
45
+ end
46
+
47
+ # Lint all definitions in register
48
+ def lint_all
49
+ register_path = options[:register] || Ukiryu::Register.default_register_path
50
+ return say_error("Register not found: #{register_path}") unless Dir.exist?(register_path)
51
+
52
+ tools_dir = File.join(register_path, 'tools')
53
+ return say_error("Tools directory not found: #{tools_dir}") unless Dir.exist?(tools_dir)
54
+
55
+ results = {}
56
+ total_issues = 0
57
+
58
+ Dir.glob(File.join(tools_dir, '*', '*', '*.yaml')).each do |file|
59
+ result = Ukiryu::Definition::DefinitionLinter.lint_file(file)
60
+ results[file] = result
61
+ total_issues += result.count
62
+ end
63
+
64
+ # Summary
65
+ total_files = results.length
66
+ total_errors = results.values.sum(&:error_count)
67
+ total_warnings = results.values.sum { |r| r.count_by_severity(Ukiryu::Definition::LintIssue::SEVERITY_WARNING) }
68
+
69
+ say "\nLint Summary:", :cyan
70
+ say " Files: #{total_files}", :white
71
+ say " Issues: #{total_issues}", total_issues.zero? ? :green : :white
72
+ say " Errors: #{total_errors}", total_errors.zero? ? :green : :red
73
+ say " Warnings: #{total_warnings}", :white
74
+
75
+ # Show files with issues
76
+ if total_issues.positive?
77
+ say '', :clear
78
+ say 'Files with Issues:', :yellow
79
+
80
+ results.each do |file, result|
81
+ next unless result.has_issues?
82
+
83
+ status = result.has_errors? ? '✗' : '⚠'
84
+ say " #{status} #{file} (#{result.count} issues)", :white
85
+ end
86
+ end
87
+
88
+ exit 1 if total_errors.positive?
89
+ end
90
+
91
+ # List all linting rules
92
+ def list_rules
93
+ say 'Linting Rules:', :cyan
94
+ say '', :clear
95
+
96
+ say 'Naming Convention Rules:', :white
97
+ say ' naming_tool_name_format - Tool name format', :dim
98
+ say ' naming_command_name_format - Command name format', :dim
99
+ say '', :clear
100
+
101
+ say 'Completeness Rules:', :white
102
+ say ' complete_missing_description - Missing description', :dim
103
+ say ' complete_missing_homepage - Missing homepage', :dim
104
+ say ' complete_missing_version_detection - Missing version detection', :dim
105
+ say '', :clear
106
+
107
+ say 'Security Rules:', :white
108
+ say ' security_suspicious_subcommand - Dangerous shell commands', :dim
109
+ say ' security_unvalidated_input - Arguments without type validation', :dim
110
+ say '', :clear
111
+
112
+ say 'Best Practice Rules:', :white
113
+ say ' style_redundant_default_profile - Redundant default profile', :dim
114
+ say ' complete_missing_platforms - Missing platforms specification', :dim
115
+ end
116
+
117
+ # Output linting result
118
+ #
119
+ # @param result [LintResult] linting result
120
+ # @param source [String] source identifier
121
+ def output_result(result, source)
122
+ case options[:format]
123
+ when 'json'
124
+ say result.to_h.to_json, :white
125
+ else
126
+ output_text(result, source)
127
+ end
128
+ end
129
+
130
+ # Output as text
131
+ #
132
+ # @param result [LintResult] linting result
133
+ # @param source [String] source identifier
134
+ def output_text(result, source)
135
+ say "Linting: #{source}", :cyan
136
+
137
+ if result.has_issues?
138
+ say "\nFound #{result.count} issue(s):", :yellow
139
+
140
+ {
141
+ Ukiryu::Definition::LintIssue::SEVERITY_ERROR => 'Errors',
142
+ Ukiryu::Definition::LintIssue::SEVERITY_WARNING => 'Warnings',
143
+ Ukiryu::Definition::LintIssue::SEVERITY_INFO => 'Info',
144
+ Ukiryu::Definition::LintIssue::SEVERITY_STYLE => 'Style'
145
+ }.each do |severity, label|
146
+ issues = result.by_severity(severity)
147
+ next if issues.empty?
148
+
149
+ say '', :clear
150
+ say "#{label}:", severity == :error ? :red : :white
151
+ issues.each { |issue| say " #{issue}", :white }
152
+ end
153
+ else
154
+ say "\n✓ No issues found", :green
155
+ end
156
+ end
157
+
158
+ # Show error message
159
+ #
160
+ # @param message [String] error message
161
+ def say_error(message)
162
+ say message, :red
163
+ exit 1
164
+ end
165
+ end
166
+ end
167
+ end
@@ -2,18 +2,18 @@
2
2
 
3
3
  require_relative 'base_command'
4
4
  require_relative '../tool'
5
- require_relative '../registry'
5
+ require_relative '../register'
6
6
 
7
7
  module Ukiryu
8
8
  module CliCommands
9
- # List all available tools in the registry
9
+ # List all available tools in the register
10
10
  class ListCommand < BaseCommand
11
11
  # Execute the list command
12
12
  def run
13
- setup_registry
13
+ setup_register
14
14
 
15
- tools = Registry.tools
16
- error! 'No tools found in registry' if tools.empty?
15
+ tools = Register.tools
16
+ error! 'No tools found in register' if tools.empty?
17
17
 
18
18
  say "Available tools (#{tools.count}):", :cyan
19
19
 
@@ -22,7 +22,7 @@ module Ukiryu
22
22
  standalone_tools = []
23
23
 
24
24
  tools.sort.each do |name|
25
- metadata = Registry.load_tool_metadata(name.to_sym)
25
+ metadata = Register.load_tool_metadata(name.to_sym)
26
26
 
27
27
  if metadata&.implements
28
28
  # This tool implements an interface
@@ -12,11 +12,11 @@ module Ukiryu
12
12
  # @param tool_name [String] the tool name
13
13
  # @param command_name [String, nil] optional command name
14
14
  def run(tool_name, command_name = nil)
15
- setup_registry
15
+ setup_register
16
16
 
17
17
  # Use find_by for interface-based discovery (ping -> ping_bsd/ping_gnu)
18
18
  tool = Tool.find_by(tool_name.to_sym)
19
- error!("Tool not found: #{tool_name}\nAvailable tools: #{Registry.tools.sort.join(', ')}") unless tool
19
+ error!("Tool not found: #{tool_name}\nAvailable tools: #{Register.tools.sort.join(', ')}") unless tool
20
20
 
21
21
  tool_commands = tool.commands
22
22
  error! "No commands defined for #{tool_name}" unless tool_commands
@@ -12,7 +12,7 @@ module Ukiryu
12
12
  # @param tool_name [String] the tool name
13
13
  # @param command_name [String, nil] optional command name
14
14
  def run(tool_name, command_name = nil)
15
- setup_registry
15
+ setup_register
16
16
 
17
17
  tool = Tool.get(tool_name)
18
18
  tool_commands = tool.commands
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../register_auto_manager'
4
+ require_relative '../register'
5
+
6
+ module Ukiryu
7
+ module CliCommands
8
+ # Command to manage the register
9
+ class RegisterCommand < BaseCommand
10
+ # Run the register command
11
+ #
12
+ # @param subcommand [String, nil] the subcommand (info, update, etc.)
13
+ # @param options [Hash] command options
14
+ # @option options [Boolean] :force force re-clone
15
+ # @option options [Boolean] :verbose show verbose output
16
+ def run(subcommand = nil, options = {})
17
+ case subcommand
18
+ when 'info', nil
19
+ show_info(options)
20
+ when 'update'
21
+ update_register(options)
22
+ when 'path'
23
+ show_path
24
+ else
25
+ error!("Unknown subcommand: #{subcommand}. Valid subcommands: info, update, path")
26
+ end
27
+ rescue RegisterAutoManager::RegisterError => e
28
+ error!("Register error: #{e.message}")
29
+ end
30
+
31
+ private
32
+
33
+ # Show register information
34
+ #
35
+ # @param options [Hash] command options
36
+ def show_info(_options = {})
37
+ info = RegisterAutoManager.register_info
38
+
39
+ say 'Register Information', :cyan
40
+ say ''
41
+
42
+ case info[:status]
43
+ when :not_found
44
+ say ' Status: Not configured', :red
45
+ say ''
46
+ say ' No register found. Run: ukiryu register update', :yellow
47
+ when :not_cloned
48
+ say ' Status: Not cloned', :yellow
49
+ say " Expected path: #{info[:path]}", :dim
50
+ say ''
51
+ say ' Run: ukiryu register update', :yellow
52
+ when :invalid
53
+ say ' Status: Invalid', :red
54
+ say " Path: #{info[:path]}", :dim
55
+ say ''
56
+ say ' Register is corrupted. Run: ukiryu register update --force', :yellow
57
+ when :ok
58
+ say ' Status: OK', :green
59
+ say " Path: #{info[:path]}", :dim
60
+ say " Source: #{format_source(info[:source])}", :dim
61
+
62
+ say " Tools available: #{info[:tools_count]}", :dim if info[:tools_count]
63
+
64
+ say " Branch: #{info[:branch]}", :dim if info[:branch]
65
+
66
+ say " Commit: #{info[:commit]}", :dim if info[:commit]
67
+
68
+ say " Last updated: #{info[:last_update].strftime('%Y-%m-%d %H:%M:%S')}", :dim if info[:last_update]
69
+ end
70
+
71
+ say ''
72
+ say 'Environment variable:', :cyan
73
+ env_path = ENV['UKIRYU_REGISTER']
74
+ if env_path
75
+ say " UKIRYU_REGISTER=#{env_path}", :dim
76
+ else
77
+ say ' UKIRYU_REGISTER (not set)', :dim
78
+ end
79
+
80
+ show_manual_setup_help if info[:status] != :ok
81
+ end
82
+
83
+ # Update the register
84
+ #
85
+ # @param options [Hash] command options
86
+ def update_register(options = {})
87
+ force = options[:force] || false
88
+
89
+ if force
90
+ say 'Force re-cloning register...', :yellow
91
+ else
92
+ say 'Updating register...', :cyan
93
+ end
94
+
95
+ RegisterAutoManager.update_register(force: force)
96
+
97
+ say 'Register updated successfully!', :green
98
+ show_info(options)
99
+ end
100
+
101
+ # Show the register path
102
+ def show_path
103
+ path = RegisterAutoManager.register_path
104
+
105
+ if path
106
+ say path
107
+ else
108
+ error!('Register not available. Run: ukiryu register update')
109
+ end
110
+ end
111
+
112
+ # Format the source for display
113
+ #
114
+ # @param source [Symbol] the source symbol
115
+ # @return [String] formatted source
116
+ def format_source(source)
117
+ case source
118
+ when :env
119
+ 'Environment variable (UKIRYU_REGISTER)'
120
+ when :dev
121
+ 'Development mode (local submodule)'
122
+ when :user
123
+ 'User local clone (~/.ukiryu/register)'
124
+ else
125
+ source.to_s
126
+ end
127
+ end
128
+
129
+ # Show manual setup help
130
+ def show_manual_setup_help
131
+ say ''
132
+ say 'Manual setup:', :cyan
133
+ say ''
134
+ say ' 1. Clone the register:'
135
+ say " git clone #{RegisterAutoManager::REGISTER_URL} ~/.ukiryu/register"
136
+ say ''
137
+ say ' 2. Or set environment variable:'
138
+ say ' export UKIRYU_REGISTER=/path/to/register'
139
+ say ''
140
+ say ' 3. Then run this command again.'
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_command'
4
+ require_relative '../definition/discovery'
5
+ require_relative '../definition/version_resolver'
6
+
7
+ module Ukiryu
8
+ module CliCommands
9
+ # Resolve tool definitions
10
+ #
11
+ # The resolve command shows which definition would be used for a tool.
12
+ class ResolveCommand < BaseCommand
13
+ # Execute the resolve command
14
+ #
15
+ # @param tool_name [String] the tool name to resolve
16
+ # @param version_constraint [String, nil] optional version constraint
17
+ def run(tool_name, version_constraint = nil)
18
+ if tool_name.nil?
19
+ say 'Error: Tool name is required', :red
20
+ say '', :clear
21
+ say 'Usage: ukiryu resolve TOOL [VERSION_CONSTRAINT]', :white
22
+ exit 1
23
+ end
24
+
25
+ # Resolve the definition
26
+ resolve_definition(tool_name, version_constraint)
27
+ end
28
+
29
+ private
30
+
31
+ # Resolve which definition would be used
32
+ #
33
+ # @param tool_name [String] the tool name
34
+ # @param version_constraint [String, nil] optional version constraint
35
+ def resolve_definition(tool_name, version_constraint)
36
+ # Get all available definitions for the tool
37
+ definitions = Ukiryu::Definition::Discovery.definitions_for(tool_name)
38
+
39
+ if definitions.empty?
40
+ say "Resolution for: #{tool_name}", :cyan
41
+ say '', :clear
42
+ say "✗ No definitions found for '#{tool_name}'", :red
43
+ say '', :clear
44
+ say 'To see available tools:', :cyan
45
+ say ' ukiryu list', :white
46
+ say '', :clear
47
+ say 'To search for definitions:', :cyan
48
+ say ' ukiryu definitions list', :white
49
+ exit 1
50
+ end
51
+
52
+ say "Resolution for: #{tool_name}", :cyan
53
+ say '', :clear
54
+
55
+ # Show all available definitions
56
+ say "Available Definitions (#{definitions.size}):", :white
57
+ definitions.each do |metadata|
58
+ priority_icon = priority_icon(metadata.priority)
59
+ say " #{priority_icon} #{metadata.version} (#{metadata.source_type})", :white
60
+ say " Path: #{metadata.path}", :dim
61
+ say " Mtime: #{metadata.mtime}", :dim
62
+ say " Priority: #{metadata.priority}", :dim
63
+ say '', :clear
64
+ end
65
+
66
+ # Determine which definition would be used
67
+ if version_constraint
68
+ # Resolve with version constraint
69
+ available_versions = definitions.map(&:version)
70
+ selected_version = Ukiryu::Definition::VersionResolver.resolve(
71
+ version_constraint,
72
+ available_versions
73
+ )
74
+
75
+ if selected_version
76
+ selected_metadata = definitions.find { |d| d.version == selected_version }
77
+ say "Selected Definition (constraint: #{version_constraint}):", :cyan
78
+ say " ✓ #{selected_metadata.name}/#{selected_metadata.version}", :green
79
+ say " Source: #{selected_metadata.source_type}", :white
80
+ say " Path: #{selected_metadata.path}", :white
81
+ else
82
+ say "✗ No version satisfies constraint: #{version_constraint}", :red
83
+ say '', :clear
84
+ say 'Available versions:', :white
85
+ available_versions.each do |v|
86
+ say " - #{v}", :dim
87
+ end
88
+ exit 1
89
+ end
90
+ else
91
+ # Use highest priority definition
92
+ selected_metadata = definitions.first
93
+
94
+ say 'Selected Definition (highest priority):', :cyan
95
+ say " ✓ #{selected_metadata.name}/#{selected_metadata.version}", :green
96
+ say " Source: #{selected_metadata.source_type}", :white
97
+ say " Path: #{selected_metadata.path}", :white
98
+ say " Priority: #{selected_metadata.priority}", :white
99
+ end
100
+
101
+ # Check if definition exists and is valid
102
+ return unless selected_metadata && !selected_metadata.exists?
103
+
104
+ say '', :clear
105
+ say '⚠ Warning: Definition file does not exist!', :yellow
106
+ end
107
+
108
+ # Get priority icon
109
+ #
110
+ # @param priority [Integer] the priority value
111
+ # @return [String] icon character
112
+ def priority_icon(priority)
113
+ case priority
114
+ when 1 then '★' # User
115
+ when 2 then '◆' # Bundled
116
+ when 3 then '■' # Local system
117
+ when 4 then '□' # System
118
+ when 5 then '△' # Register
119
+ else '·'
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -22,7 +22,7 @@ module Ukiryu
22
22
  # @param command_name [String, nil] the command name (optional, uses default if nil)
23
23
  # @param params [Array<String>] key=value parameter pairs
24
24
  def run(tool_name, command_name = nil, *params)
25
- setup_registry
25
+ setup_register
26
26
 
27
27
  # Handle the case where command_name is omitted and first param is a key=value pair
28
28
  # When user types: ukiryu exec-inline ping host=127.0.0.1
@@ -80,7 +80,7 @@ module Ukiryu
80
80
  debug: config.debug,
81
81
  dry_run: config.dry_run,
82
82
  output: config.output,
83
- registry: config.registry,
83
+ register: config.register,
84
84
  stdin: !arguments[:stdin].nil?
85
85
  }
86
86
  logger.debug_section_ukiryu_options(ukiryu_options)
@@ -119,13 +119,19 @@ module Ukiryu
119
119
  # @param tool_name [String] the tool name
120
120
  # @return [String] the resolved command name
121
121
  def resolve_default_command(tool_name)
122
- # Use Registry to load tool metadata without full resolution
123
- # This avoids triggering debug output for "Tool Resolution" twice
124
- require_relative '../registry'
125
- require_relative '../models/tool_metadata'
122
+ # If --definition is provided, load from definition file
123
+ if options[:definition]
124
+ tool = Tool.load(options[:definition], validation: :strict)
125
+ metadata = tool.profile
126
+ else
127
+ # Use Register to load tool metadata without full resolution
128
+ # This avoids triggering debug output for "Tool Resolution" twice
129
+ require_relative '../register'
130
+ require_relative '../models/tool_metadata'
126
131
 
127
- metadata = Registry.load_tool_metadata(tool_name.to_sym, registry_path: config.registry)
128
- error! "Tool not found: #{tool_name}" unless metadata
132
+ metadata = Register.load_tool_metadata(tool_name.to_sym, register_path: config.register)
133
+ error! "Tool not found: #{tool_name}" unless metadata
134
+ end
129
135
 
130
136
  # Get the default command (checks YAML default_command, then implements, then tool name)
131
137
  command = metadata.default_command
@@ -194,8 +200,20 @@ module Ukiryu
194
200
  # Stage: Tool Resolution
195
201
  execution_report.tool_resolution.start! if collect_metrics
196
202
 
197
- # Get tool - try find_by first for interface-based discovery, fallback to get
198
- tool = Tool.find_by(tool_name.to_sym) || Tool.get(tool_name.to_sym)
203
+ # Load tool from definition file if --definition option provided
204
+ if options[:definition]
205
+ tool = Tool.load(options[:definition], validation: :strict)
206
+ # Verify that the tool name matches (if user specified one)
207
+ if tool_name && tool.name.to_sym != tool_name.to_sym
208
+ return Models::ErrorResponse.from_message(
209
+ "Tool name mismatch: definition file contains '#{tool.name}' but command specified '#{tool_name}'"
210
+ )
211
+ end
212
+ else
213
+ # Get tool - try find_by first for interface-based discovery, fallback to get
214
+ tool = Tool.find_by(tool_name.to_sym) || Tool.get(tool_name.to_sym)
215
+ end
216
+
199
217
  return Models::ErrorResponse.from_message("Tool not available: #{tool_name}") unless tool
200
218
 
201
219
  return Models::ErrorResponse.from_message("Tool found but not executable: #{tool_name}") unless tool.available?
@@ -324,11 +342,17 @@ module Ukiryu
324
342
  # @param tool_name [String] the tool name
325
343
  # @param params [Array<String>] additional parameters
326
344
  def show_tool_help(tool_name, _params = [])
327
- setup_registry
345
+ setup_register
346
+
347
+ # Load tool from definition file if --definition option provided
348
+ tool = if options[:definition]
349
+ Tool.load(options[:definition], validation: :strict)
350
+ else
351
+ # Use find_by for interface-based discovery
352
+ Tool.find_by(tool_name.to_sym)
353
+ end
328
354
 
329
- # Use find_by for interface-based discovery
330
- tool = Tool.find_by(tool_name.to_sym)
331
- error! "Tool not found: #{tool_name}\nAvailable tools: #{Registry.tools.sort.join(', ')}" unless tool
355
+ error! "Tool not found: #{tool_name}\nAvailable tools: #{Register.tools.sort.join(', ')}" unless tool
332
356
 
333
357
  say '', :clear
334
358
  say "Tool: #{tool.name}", :cyan
@@ -20,7 +20,7 @@ module Ukiryu
20
20
  #
21
21
  # @param request_file [String] path to the request YAML file
22
22
  def run(request_file)
23
- setup_registry
23
+ setup_register
24
24
 
25
25
  # Output debug: Ukiryu CLI Options
26
26
  if config.debug
@@ -30,7 +30,7 @@ module Ukiryu
30
30
  debug: config.debug,
31
31
  dry_run: config.dry_run,
32
32
  output: config.output,
33
- registry: config.registry,
33
+ register: config.register,
34
34
  request_file: request_file
35
35
  }
36
36
  logger.debug_section_ukiryu_options(ukiryu_options)