ace-support-nav 0.25.0

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/nav/config.yml +33 -0
  3. data/.ace-defaults/nav/protocols/guide-sources/ace-support-nav.yml +7 -0
  4. data/.ace-defaults/nav/protocols/guide.yml +69 -0
  5. data/.ace-defaults/nav/protocols/prompt.yml +39 -0
  6. data/.ace-defaults/nav/protocols/skill-sources/ace-support-nav.yml +19 -0
  7. data/.ace-defaults/nav/protocols/skill.yml +22 -0
  8. data/.ace-defaults/nav/protocols/tmpl-sources/ace-support-nav.yml +7 -0
  9. data/.ace-defaults/nav/protocols/tmpl.yml +55 -0
  10. data/.ace-defaults/nav/protocols/wfi-sources/ace-support-nav.yml +7 -0
  11. data/.ace-defaults/nav/protocols/wfi.yml +61 -0
  12. data/CHANGELOG.md +231 -0
  13. data/LICENSE +21 -0
  14. data/README.md +48 -0
  15. data/Rakefile +12 -0
  16. data/docs/demo/ace-support-nav-getting-started.gif +0 -0
  17. data/docs/demo/ace-support-nav-getting-started.tape.yml +28 -0
  18. data/exe/ace-nav +49 -0
  19. data/handbook/workflow-instructions/test.wfi.md +14 -0
  20. data/lib/ace/support/nav/atoms/extension_inferrer.rb +134 -0
  21. data/lib/ace/support/nav/atoms/gem_resolver.rb +59 -0
  22. data/lib/ace/support/nav/atoms/path_normalizer.rb +52 -0
  23. data/lib/ace/support/nav/atoms/uri_parser.rb +62 -0
  24. data/lib/ace/support/nav/cli/commands/create.rb +114 -0
  25. data/lib/ace/support/nav/cli/commands/list.rb +122 -0
  26. data/lib/ace/support/nav/cli/commands/resolve.rb +187 -0
  27. data/lib/ace/support/nav/cli/commands/sources.rb +112 -0
  28. data/lib/ace/support/nav/cli.rb +66 -0
  29. data/lib/ace/support/nav/models/handbook_source.rb +73 -0
  30. data/lib/ace/support/nav/models/protocol_source.rb +104 -0
  31. data/lib/ace/support/nav/models/resource.rb +46 -0
  32. data/lib/ace/support/nav/models/resource_uri.rb +78 -0
  33. data/lib/ace/support/nav/molecules/config_loader.rb +275 -0
  34. data/lib/ace/support/nav/molecules/handbook_scanner.rb +204 -0
  35. data/lib/ace/support/nav/molecules/protocol_scanner.rb +434 -0
  36. data/lib/ace/support/nav/molecules/resource_resolver.rb +134 -0
  37. data/lib/ace/support/nav/molecules/source_registry.rb +133 -0
  38. data/lib/ace/support/nav/organisms/command_delegator.rb +122 -0
  39. data/lib/ace/support/nav/organisms/navigation_engine.rb +180 -0
  40. data/lib/ace/support/nav/version.rb +9 -0
  41. data/lib/ace/support/nav.rb +104 -0
  42. metadata +228 -0
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+ require_relative "../molecules/config_loader"
5
+
6
+ module Ace
7
+ module Support
8
+ module Nav
9
+ module Organisms
10
+ # Handles command delegation for cmd-type protocols
11
+ # Executes external commands based on protocol configuration templates
12
+ class CommandDelegator
13
+ def initialize(config_loader: nil)
14
+ @config_loader = config_loader || Molecules::ConfigLoader.new
15
+ end
16
+
17
+ # Delegate a URI to an external command
18
+ # @param uri_string [String] The URI to delegate (e.g., "task://083")
19
+ # @param options [Hash] Options from CLI (e.g., {path: true, content: true})
20
+ # @return [Integer] Exit code from the delegated command
21
+ def delegate(uri_string, options = {})
22
+ # Parse the URI to extract protocol and reference
23
+ protocol, reference = parse_uri(uri_string)
24
+
25
+ # Load protocol configuration
26
+ protocol_config = @config_loader.load_protocol_config(protocol)
27
+
28
+ # Verify this is a cmd-type protocol
29
+ unless protocol_config["type"] == "cmd"
30
+ raise ArgumentError, "Protocol #{protocol} is not a cmd-type protocol"
31
+ end
32
+
33
+ # Get command template
34
+ command_template = protocol_config["command_template"]
35
+ unless command_template
36
+ raise ArgumentError, "Protocol #{protocol} missing command_template"
37
+ end
38
+
39
+ # Build the command
40
+ command_parts = build_command(command_template, reference, options, protocol_config)
41
+
42
+ # Execute the command
43
+ execute_command(command_parts)
44
+ end
45
+
46
+ private
47
+
48
+ # Parse a URI into protocol and reference
49
+ # @param uri_string [String] URI like "task://083" or "task://v.0.9.0+task.083"
50
+ # @return [Array<String, String>] [protocol, reference]
51
+ def parse_uri(uri_string)
52
+ unless uri_string.include?("://")
53
+ raise ArgumentError, "Invalid URI format: #{uri_string}"
54
+ end
55
+
56
+ parts = uri_string.split("://", 2)
57
+ protocol = parts[0]
58
+ reference = parts[1] || ""
59
+
60
+ [protocol, reference]
61
+ end
62
+
63
+ # Build command array from template and options
64
+ # @param template [String] Command template with %{ref} placeholder
65
+ # @param reference [String] The resource reference to substitute
66
+ # @param options [Hash] CLI options to pass through
67
+ # @param protocol_config [Hash] Protocol configuration
68
+ # @return [Array<String>] Command parts as array for safe execution
69
+ #
70
+ # @note Template parsing uses Shellwords.split() for robust parsing of command
71
+ # templates, properly handling quoted strings and complex argument patterns.
72
+ def build_command(template, reference, options, protocol_config)
73
+ # Substitute reference in template
74
+ command_string = template.gsub("%{ref}", reference)
75
+
76
+ # Parse command using Shellwords for robust handling of quotes and spaces
77
+ command_parts = Shellwords.split(command_string)
78
+
79
+ # Add pass-through options
80
+ pass_through_options = protocol_config["pass_through_options"] || []
81
+
82
+ options.each do |key, value|
83
+ option_flag = "--#{key.to_s.tr("_", "-")}"
84
+
85
+ # Only add if it's in pass_through list or if we don't have a list
86
+ if pass_through_options.empty? || pass_through_options.include?(option_flag)
87
+ if value == true
88
+ command_parts << option_flag
89
+ elsif value.is_a?(String)
90
+ command_parts << option_flag
91
+ command_parts << value
92
+ end
93
+ end
94
+ end
95
+
96
+ command_parts
97
+ end
98
+
99
+ # Execute command using system and return exit code
100
+ # @param command_parts [Array<String>] Command parts for safe execution
101
+ # @return [Integer] Exit code (0 for success, 1 for failure)
102
+ def execute_command(command_parts)
103
+ # Use system with array argument for safety (no shell interpolation)
104
+ success = system(*command_parts)
105
+
106
+ # Return exit code
107
+ if success.nil?
108
+ # Command not found
109
+ warn "Error: Command not found: #{command_parts[0]}"
110
+ warn "Please install the required gem or ensure it's in your PATH"
111
+ 1
112
+ elsif success
113
+ 0
114
+ else
115
+ $?.exitstatus || 1
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../molecules/protocol_scanner"
4
+ require_relative "../molecules/resource_resolver"
5
+ require_relative "../atoms/path_normalizer"
6
+
7
+ module Ace
8
+ module Support
9
+ module Nav
10
+ module Organisms
11
+ # Orchestrates navigation operations
12
+ class NavigationEngine
13
+ def initialize(handbook_scanner: nil, protocol_scanner: nil, resource_resolver: nil, path_normalizer: nil)
14
+ # Support legacy handbook_scanner parameter
15
+ @protocol_scanner = protocol_scanner || handbook_scanner || Molecules::ProtocolScanner.new
16
+ @resource_resolver = resource_resolver || Molecules::ResourceResolver.new(protocol_scanner: @protocol_scanner)
17
+ @path_normalizer = path_normalizer || Atoms::PathNormalizer.new
18
+ end
19
+
20
+ # Resolve a single resource URI to a path
21
+ def resolve(uri_string, options = {})
22
+ resource = @resource_resolver.resolve(uri_string)
23
+ return nil unless resource
24
+
25
+ if options[:content]
26
+ resource.content
27
+ elsif options[:verbose]
28
+ resource.to_h
29
+ else
30
+ resource.path
31
+ end
32
+ end
33
+
34
+ # List resources matching a pattern
35
+ def list(uri_pattern, options = {})
36
+ resources = @resource_resolver.resolve_pattern(uri_pattern)
37
+
38
+ if options[:tree]
39
+ format_as_tree(resources)
40
+ elsif options[:verbose]
41
+ resources.map(&:to_h)
42
+ else
43
+ format_as_list(resources)
44
+ end
45
+ end
46
+
47
+ # Create a new resource from a template
48
+ def create(uri_string, target_path = nil)
49
+ # Resolve the template
50
+ template = @resource_resolver.resolve(uri_string)
51
+ return {error: "Template not found: #{uri_string}"} unless template
52
+
53
+ # Determine target path
54
+ target = determine_target_path(template, target_path)
55
+ return {error: "Could not determine target path"} unless target
56
+
57
+ # Create directory if needed
58
+ target_dir = File.dirname(target)
59
+ FileUtils.mkdir_p(target_dir) unless Dir.exist?(target_dir)
60
+
61
+ # Copy template content
62
+ if template.content
63
+ File.write(target, template.content)
64
+ {created: target, from: template.path}
65
+ else
66
+ {error: "Template has no content: #{template.path}"}
67
+ end
68
+ end
69
+
70
+ # Show available sources
71
+ def sources(options = {})
72
+ all_sources = @protocol_scanner.scan_all_sources
73
+
74
+ if options[:verbose]
75
+ all_sources.map(&:to_h)
76
+ else
77
+ all_sources.map { |s| "#{s.alias_name} (#{s.type}): #{s.path}" }
78
+ end
79
+ end
80
+
81
+ # Get all discovered protocols
82
+ def discovered_protocols
83
+ config_loader.discovered_protocols
84
+ end
85
+
86
+ # Check if a protocol is cmd-type (command delegation)
87
+ # @param protocol_name [String] The protocol name to check
88
+ # @return [Boolean] true if protocol delegates to external command
89
+ def cmd_protocol?(protocol_name)
90
+ config_loader.protocol_type(protocol_name) == "cmd"
91
+ end
92
+
93
+ # Resolve a cmd-type protocol URI by running its command and capturing stdout
94
+ # Used by tools that need to programmatically obtain the resolved path
95
+ # @param uri_string [String] e.g., "task://8c0.t.05p"
96
+ # @return [String, nil] captured stdout (path), or nil on failure
97
+ def resolve_cmd_to_path(uri_string)
98
+ protocol, reference = uri_string.split("://", 2)
99
+ return nil unless cmd_protocol?(protocol)
100
+
101
+ protocol_config = config_loader.load_protocol_config(protocol)
102
+ command_template = protocol_config["command_template"]
103
+ return nil unless command_template
104
+
105
+ require "open3"
106
+ require "shellwords"
107
+ require "timeout"
108
+ args = Shellwords.split(command_template.gsub("%{ref}", Shellwords.escape(reference)))
109
+ stdout, status = Timeout.timeout(10) { Open3.capture2(*args) }
110
+ return nil unless status.success?
111
+
112
+ result = stdout.strip
113
+ result.empty? ? nil : result
114
+ rescue Timeout::Error
115
+ warn "Warning: cmd protocol timed out for '#{uri_string}'"
116
+ nil
117
+ end
118
+
119
+ private
120
+
121
+ def format_as_list(resources)
122
+ resources.map do |resource|
123
+ "#{resource.uri} → #{resource.path} (#{resource.source.alias_name})"
124
+ end
125
+ end
126
+
127
+ def format_as_tree(resources)
128
+ # Group by source
129
+ by_source = resources.group_by { |r| r.source.alias_name }
130
+
131
+ tree = []
132
+ by_source.each do |source_alias, source_resources|
133
+ tree << "#{source_alias}/"
134
+
135
+ # Group by protocol
136
+ by_protocol = source_resources.group_by(&:protocol)
137
+ by_protocol.each do |protocol, protocol_resources|
138
+ tree << " #{protocol}://"
139
+
140
+ # Sort and display resources
141
+ protocol_resources.sort_by(&:resource_path).each do |resource|
142
+ tree << " #{resource.resource_path}"
143
+ end
144
+ end
145
+ end
146
+
147
+ tree
148
+ end
149
+
150
+ def determine_target_path(template, target_path)
151
+ # If explicit target provided, use it
152
+ return @path_normalizer.normalize(target_path) if target_path
153
+
154
+ # Otherwise, create in project .ace-handbook
155
+ project_handbook = File.expand_path("./.ace-handbook")
156
+
157
+ # Determine subdirectory based on protocol
158
+ subdir = case template.protocol
159
+ when "wfi" then "workflow-instructions"
160
+ when "tmpl" then "templates"
161
+ when "guide" then "guides"
162
+ when "sample" then "samples"
163
+ else template.protocol
164
+ end
165
+
166
+ # Build target path
167
+ filename = File.basename(template.path)
168
+ File.join(project_handbook, subdir, filename)
169
+ end
170
+
171
+ # Access the config_loader from protocol_scanner
172
+ # Reuses the same ConfigLoader instance across all protocol operations
173
+ def config_loader
174
+ @protocol_scanner.config_loader
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Support
5
+ module Nav
6
+ VERSION = "0.25.0"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "nav/version"
4
+ require "ace/support/config"
5
+
6
+ # Load all ace-support-nav components
7
+ require_relative "nav/cli"
8
+ require_relative "nav/atoms/gem_resolver"
9
+ require_relative "nav/atoms/path_normalizer"
10
+ require_relative "nav/atoms/uri_parser"
11
+ require_relative "nav/molecules/config_loader"
12
+ require_relative "nav/molecules/handbook_scanner"
13
+ require_relative "nav/molecules/protocol_scanner"
14
+ require_relative "nav/molecules/resource_resolver"
15
+ require_relative "nav/molecules/source_registry"
16
+ require_relative "nav/organisms/navigation_engine"
17
+ require_relative "nav/organisms/command_delegator"
18
+ require_relative "nav/models/handbook_source"
19
+ require_relative "nav/models/protocol_source"
20
+ require_relative "nav/models/resource"
21
+ require_relative "nav/models/resource_uri"
22
+
23
+ module Ace
24
+ module Support
25
+ module Nav
26
+ class Error < StandardError; end
27
+
28
+ # Initialize mutex for thread-safe config access
29
+ @config_mutex = Mutex.new
30
+
31
+ # Returns the gem root directory
32
+ # Used by command files to locate .ace-defaults/ configuration
33
+ # Centralizes the path calculation to avoid duplication across commands
34
+ # @return [String] Path to the gem root directory
35
+ def self.gem_root
36
+ @gem_root ||= Gem.loaded_specs["ace-support-nav"]&.gem_dir ||
37
+ File.expand_path("../../..", __dir__)
38
+ end
39
+
40
+ # Check if debug mode is enabled
41
+ # @return [Boolean] True if debug mode is enabled
42
+ def self.debug?
43
+ ENV["ACE_DEBUG"] == "1" || ENV["DEBUG"] == "1"
44
+ end
45
+
46
+ # Load ace-support-nav configuration using ace-config cascade
47
+ # Follows ADR-022: Configuration Default and Override Pattern
48
+ # Uses Ace::Support::Config.create() for configuration cascade resolution
49
+ # Thread-safe: uses mutex for initialization
50
+ # @return [Hash] Configuration hash with defaults merged
51
+ def self.config
52
+ # Fast path: return cached config if already initialized
53
+ return @config if defined?(@config) && @config
54
+
55
+ # Thread-safe initialization
56
+ @config_mutex.synchronize do
57
+ @config ||= load_config
58
+ end
59
+ end
60
+
61
+ # Reset config cache (useful for testing)
62
+ # Thread-safe: uses mutex to prevent race conditions
63
+ def self.reset_config!
64
+ @config_mutex.synchronize do
65
+ @config = nil
66
+ end
67
+ end
68
+
69
+ # Load configuration using Ace::Support::Config cascade
70
+ # @return [Hash] Merged configuration
71
+ def self.load_config
72
+ resolver = Ace::Support::Config.create(
73
+ config_dir: ".ace",
74
+ defaults_dir: ".ace-defaults",
75
+ gem_path: gem_root
76
+ )
77
+
78
+ # Resolve config for nav namespace
79
+ config = resolver.resolve_namespace("nav")
80
+ config.data
81
+ rescue => e
82
+ warn "ace-support-nav: Could not load config: #{e.class} - #{e.message}" if debug?
83
+ # Fall back to gem defaults instead of empty hash to prevent silent config erasure
84
+ load_gem_defaults_fallback
85
+ end
86
+ private_class_method :load_config
87
+
88
+ # Load gem defaults directly as fallback when cascade resolution fails
89
+ # This ensures configuration is never silently erased due to YAML errors
90
+ # or user config issues
91
+ # @return [Hash] Defaults hash or empty hash if defaults also fail
92
+ def self.load_gem_defaults_fallback
93
+ defaults_path = File.join(gem_root, ".ace-defaults", "nav", "config.yml")
94
+
95
+ return {} unless File.exist?(defaults_path)
96
+
97
+ YAML.safe_load_file(defaults_path, permitted_classes: [Date], aliases: true) || {}
98
+ rescue
99
+ {} # Only return empty hash if even defaults fail to load
100
+ end
101
+ private_class_method :load_gem_defaults_fallback
102
+ end
103
+ end
104
+ end
metadata ADDED
@@ -0,0 +1,228 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ace-support-nav
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.25.0
5
+ platform: ruby
6
+ authors:
7
+ - Michal Czyz
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ace-support-cli
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.3'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.3'
26
+ - !ruby/object:Gem::Dependency
27
+ name: ace-support-core
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.25'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.25'
40
+ - !ruby/object:Gem::Dependency
41
+ name: ace-support-config
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.8'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.8'
54
+ - !ruby/object:Gem::Dependency
55
+ name: ace-support-fs
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: ace-support-test-helpers
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.12'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.12'
82
+ - !ruby/object:Gem::Dependency
83
+ name: bundler
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: minitest
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '5.0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '5.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rake
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '13.0'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '13.0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: rubocop
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '1.50'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.50'
138
+ - !ruby/object:Gem::Dependency
139
+ name: simplecov
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '0.22'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.22'
152
+ description: ace-support-nav provides unified navigation and path resolution across
153
+ the ACE ecosystem. It automatically discovers handbooks bundled within ace-* gems,
154
+ resolves resource URIs to actual file paths, and supports a multi-level override
155
+ cascade.
156
+ email:
157
+ - mc@cs3b.com
158
+ executables:
159
+ - ace-nav
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - ".ace-defaults/nav/config.yml"
164
+ - ".ace-defaults/nav/protocols/guide-sources/ace-support-nav.yml"
165
+ - ".ace-defaults/nav/protocols/guide.yml"
166
+ - ".ace-defaults/nav/protocols/prompt.yml"
167
+ - ".ace-defaults/nav/protocols/skill-sources/ace-support-nav.yml"
168
+ - ".ace-defaults/nav/protocols/skill.yml"
169
+ - ".ace-defaults/nav/protocols/tmpl-sources/ace-support-nav.yml"
170
+ - ".ace-defaults/nav/protocols/tmpl.yml"
171
+ - ".ace-defaults/nav/protocols/wfi-sources/ace-support-nav.yml"
172
+ - ".ace-defaults/nav/protocols/wfi.yml"
173
+ - CHANGELOG.md
174
+ - LICENSE
175
+ - README.md
176
+ - Rakefile
177
+ - docs/demo/ace-support-nav-getting-started.gif
178
+ - docs/demo/ace-support-nav-getting-started.tape.yml
179
+ - exe/ace-nav
180
+ - handbook/workflow-instructions/test.wfi.md
181
+ - lib/ace/support/nav.rb
182
+ - lib/ace/support/nav/atoms/extension_inferrer.rb
183
+ - lib/ace/support/nav/atoms/gem_resolver.rb
184
+ - lib/ace/support/nav/atoms/path_normalizer.rb
185
+ - lib/ace/support/nav/atoms/uri_parser.rb
186
+ - lib/ace/support/nav/cli.rb
187
+ - lib/ace/support/nav/cli/commands/create.rb
188
+ - lib/ace/support/nav/cli/commands/list.rb
189
+ - lib/ace/support/nav/cli/commands/resolve.rb
190
+ - lib/ace/support/nav/cli/commands/sources.rb
191
+ - lib/ace/support/nav/models/handbook_source.rb
192
+ - lib/ace/support/nav/models/protocol_source.rb
193
+ - lib/ace/support/nav/models/resource.rb
194
+ - lib/ace/support/nav/models/resource_uri.rb
195
+ - lib/ace/support/nav/molecules/config_loader.rb
196
+ - lib/ace/support/nav/molecules/handbook_scanner.rb
197
+ - lib/ace/support/nav/molecules/protocol_scanner.rb
198
+ - lib/ace/support/nav/molecules/resource_resolver.rb
199
+ - lib/ace/support/nav/molecules/source_registry.rb
200
+ - lib/ace/support/nav/organisms/command_delegator.rb
201
+ - lib/ace/support/nav/organisms/navigation_engine.rb
202
+ - lib/ace/support/nav/version.rb
203
+ homepage: https://github.com/cs3b/ace
204
+ licenses:
205
+ - MIT
206
+ metadata:
207
+ allowed_push_host: https://rubygems.org
208
+ homepage_uri: https://github.com/cs3b/ace
209
+ source_code_uri: https://github.com/cs3b/ace/tree/main/ace-support-nav/
210
+ changelog_uri: https://github.com/cs3b/ace/blob/main/ace-support-nav/CHANGELOG.md
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: 3.2.0
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubygems_version: 3.6.9
226
+ specification_version: 4
227
+ summary: Unified navigation and resource discovery for ACE ecosystem
228
+ test_files: []