ace-support-nav 0.28.6 → 0.28.7

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: 1948cb2b1085585f1a3ccd40d9fddd0dd130bad2ede2991bb7922ee3dba68143
4
- data.tar.gz: 4d822e1cb78a2b43fe641d1a963cc68df74b97cda80004ce87a7520851793cef
3
+ metadata.gz: ecc4d7ddedfa6c6bb842df8618779d87b1099c1cdb3898749a8d18c77fd47095
4
+ data.tar.gz: 64cf17332d9eb5a76ccd945d4aef71c57d3b6a428b34dabe924ad532fb3205cc
5
5
  SHA512:
6
- metadata.gz: 98e6c2d42e54a1b6f272689238ffe9371256446127e22c26120489043e850b036d8438164b3fd4b64caa871391caddda8b6d2fb87222e6a485a6c02e8479902e
7
- data.tar.gz: 0b937920845694bf9268b5591793e8f73d51a01fe5f1590fdd26c1e62d5c2437e869a951f012bf37f0ff8bda2a780cf6ef74084d2d07435089affa0df496776f
6
+ metadata.gz: 1227aa081c832c78abaf75b1ccd0113495f8f103d2530f108e0e5024d331ae79cac87cfbd61a74dfee1ddfaedcd4e40b13cb1991525688acd5b529fd2588834e
7
+ data.tar.gz: 9ca8ba354761276bfc7b449ed702a5e2f175a4af82127922129671fa1d393897733af48f2a51f1141ee453ebe597a9316c222d7494453af72df4da58c8fadbcb
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.28.7] - 2026-09-27
11
+
12
+ ### Technical
13
+ - Resolve temporary test paths through symlinks.
14
+
15
+ ### Added
16
+ - `ace-nav resolve <uri> --why` prints every duplicate candidate in resolution order with its source, priority, and origin, marks the winner, and states the source-priority rule, making override precedence observable without planting probe files.
17
+
10
18
 
11
19
  ## [0.28.6] - 2026-09-02
12
20
 
@@ -39,6 +39,9 @@ module Ace
39
39
  # Display content
40
40
  $ ace-nav resolve wfi://setup --content
41
41
 
42
+ # Explain precedence: all candidates + the rule that picked the winner
43
+ $ ace-nav resolve wfi://setup --why
44
+
42
45
  # Wildcard patterns auto-route to list
43
46
  $ ace-nav resolve wfi://*
44
47
 
@@ -57,6 +60,8 @@ module Ace
57
60
 
58
61
  By default, displays resolved path
59
62
  Use --content to display resource content
63
+ Use --why to print all candidates in resolution order plus the
64
+ rule that picked the winner (useful when duplicates exist)
60
65
  Exit codes: 0 (success), 1 (error)
61
66
  DESC
62
67
 
@@ -71,6 +76,7 @@ module Ace
71
76
 
72
77
  option :path, type: :boolean, desc: "Display resource path"
73
78
  option :content, type: :boolean, desc: "Display resource content"
79
+ option :why, type: :boolean, desc: "Explain precedence: print all candidates in resolution order and the winner"
74
80
  option :tree, type: :boolean, desc: "Display resources in tree format (passed through to cmd protocols)"
75
81
  option :verbose, type: :boolean, aliases: %w[-v], desc: "Show verbose output"
76
82
  option :quiet, type: :boolean, aliases: %w[-q], desc: "Suppress non-essential output"
@@ -103,11 +109,18 @@ module Ace
103
109
  if @uri.include?("://")
104
110
  protocol = @uri.split("://").first
105
111
  if @engine.cmd_protocol?(protocol)
112
+ if @options[:why]
113
+ raise Ace::Support::Cli::Error.new("--why is not available for cmd protocols (#{protocol} delegates to an external command; there are no local candidates)")
114
+ end
106
115
  delegator = Organisms::CommandDelegator.new
107
116
  return delegator.delegate(@uri, @options)
108
117
  end
109
118
  end
110
119
 
120
+ if @options[:why]
121
+ return print_explanation(@engine.explain(@uri))
122
+ end
123
+
111
124
  result = @engine.resolve(@uri, content: @options[:content], verbose: @options[:verbose])
112
125
 
113
126
  if result.nil?
@@ -127,6 +140,28 @@ module Ace
127
140
 
128
141
  private
129
142
 
143
+ # Print a precedence explanation produced by NavigationEngine#explain
144
+ def print_explanation(explanation)
145
+ if explanation[:candidates].empty?
146
+ raise Ace::Support::Cli::Error.new("Resource not found: #{@uri}")
147
+ end
148
+
149
+ if @options[:verbose]
150
+ require "json"
151
+ puts JSON.pretty_generate(explanation)
152
+ return
153
+ end
154
+
155
+ puts "uri: #{explanation[:uri]}"
156
+ puts "rule: #{explanation[:rule]}"
157
+ puts "candidates (resolution order):"
158
+ explanation[:candidates].each do |candidate|
159
+ origin = candidate[:origin] || candidate[:source_type]
160
+ puts " #{candidate[:position]}. [priority #{candidate[:priority]}] #{candidate[:source]} (#{origin}) → #{candidate[:path]}"
161
+ puts " ← winner" if candidate[:winner]
162
+ end
163
+ end
164
+
130
165
  # Normalize bare protocol names (e.g., "wfi") to protocol:// format
131
166
  # This allows users to type "ace-nav wfi" instead of "ace-nav wfi://"
132
167
  def normalize_protocol_shorthand(uri)
@@ -17,6 +17,15 @@ module Ace
17
17
  @path_normalizer = path_normalizer || Atoms::PathNormalizer.new
18
18
  end
19
19
 
20
+ # Resolution rule applied when multiple sources register the same resource.
21
+ # Sources are ordered by ascending priority (lower number = higher precedence)
22
+ # and the first source containing the resource wins.
23
+ RESOLUTION_RULE = "Candidates are tried in ascending source-priority order " \
24
+ "(lower priority number wins); the first source containing the resource is " \
25
+ "the winner and remaining duplicates are ignored. Registration defaults: " \
26
+ "project sources 10, user sources 50, gem defaults 100 - individual source " \
27
+ "registrations may pin other values.".freeze
28
+
20
29
  # Resolve a single resource URI to a path
21
30
  def resolve(uri_string, options = {})
22
31
  resource = @resource_resolver.resolve(uri_string)
@@ -31,6 +40,28 @@ module Ace
31
40
  end
32
41
  end
33
42
 
43
+ # Explain resolution precedence for a URI
44
+ # Returns every candidate in resolution order plus the rule that picked the winner
45
+ def explain(uri_string)
46
+ candidates = @resource_resolver.resolve_pattern(uri_string)
47
+
48
+ {
49
+ uri: uri_string,
50
+ rule: RESOLUTION_RULE,
51
+ candidates: candidates.each_with_index.map do |resource, index|
52
+ {
53
+ position: index + 1,
54
+ winner: index.zero?,
55
+ path: resource.path,
56
+ source: resource.source.alias_name,
57
+ source_type: resource.source.type.to_s,
58
+ priority: resource.source.priority,
59
+ origin: resource.source.respond_to?(:origin) ? resource.source.origin : nil
60
+ }
61
+ end
62
+ }
63
+ end
64
+
34
65
  # List resources matching a pattern
35
66
  def list(uri_pattern, options = {})
36
67
  resources = @resource_resolver.resolve_pattern(uri_pattern)
@@ -3,7 +3,7 @@
3
3
  module Ace
4
4
  module Support
5
5
  module Nav
6
- VERSION = "0.28.6"
6
+ VERSION = "0.28.7"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-support-nav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.6
4
+ version: 0.28.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-09-05 00:00:00.000000000 Z
10
+ date: 2026-09-27 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ace-support-cli