Class: Ace::Support::Nav::Molecules::ConfigLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/support/nav/molecules/config_loader.rb

Overview

Loads configuration from .ace/nav/*.yml files and protocols ADR-022: Uses Ace::Support::Config.create() for gem defaults + user cascade

Defined Under Namespace

Classes: Error

Instance Method Summary collapse

Constructor Details

#initialize(config_dir = nil, source_registry: nil) ⇒ ConfigLoader

Returns a new instance of ConfigLoader.



18
19
20
21
22
23
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 18

def initialize(config_dir = nil, source_registry: nil)
  @config_dir = find_config_dir(config_dir)
  @configs = {}
  @protocols = nil  # Lazy load protocols
  @source_registry = source_registry || SourceRegistry.new
end

Instance Method Details

#available_configsObject

Get all available configuration files



121
122
123
124
125
126
127
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 121

def available_configs
  return [] unless @config_dir && Dir.exist?(@config_dir)

  Dir.glob(File.join(@config_dir, "*.yml")).map do |path|
    File.basename(path, ".yml")
  end
end

#discovered_protocolsObject

Get all discovered protocols with their metadata



130
131
132
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 130

def discovered_protocols
  load_protocols
end

#load_protocol_config(protocol) ⇒ Object

Load protocol-specific configuration



71
72
73
74
75
76
77
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 71

def load_protocol_config(protocol)
  protocols = load_protocols
  return protocols[protocol] if protocols[protocol]

  # Fallback to defaults for backward compatibility
  default_protocol_config(protocol)
end

#load_protocolsObject

Load all available protocols



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 80

def load_protocols
  return @protocols if @protocols

  @protocols = {}

  # 0. Load from gem defaults (lowest priority)
  gem_defaults_dir = File.join(Ace::Support::Nav.gem_root, ".ace-defaults", "nav", "protocols")
  load_directory_protocols(gem_defaults_dir).each do |protocol_data|
    key = protocol_data["protocol"]
    @protocols[key] = protocol_data if key
  end

  # 1. Load from user ~/.ace/nav/protocols/
  load_directory_protocols(File.expand_path("~/.ace/nav/protocols")).each do |protocol_data|
    key = protocol_data["protocol"]
    @protocols[key] = protocol_data if key
  end

  # 2. Load from project .ace/protocols/ hierarchy (highest priority)
  # Find all .ace/protocols directories from current dir up to project root
  discover_project_protocol_dirs.each do |dir|
    load_directory_protocols(dir).each do |protocol_data|
      key = protocol_data["protocol"]
      @protocols[key] = protocol_data if key
    end
  end

  @protocols
end

#load_settingsHash

Load main settings configuration ADR-022: Uses Ace::Support::Config.create() for gem defaults + user cascade

NOTE: The “nav” namespace is intentionally preserved (not “support/nav”) for backward compatibility with existing user configurations in .ace/nav/config.yml. This allows users upgrading from ace-nav to ace-support-nav to keep their config without migration. See PR #152 review discussion for context.

Returns:

  • (Hash)

    Configuration with defaults and user overrides



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 34

def load_settings
  # Return cached if already loaded
  return @configs["settings"] if @configs.key?("settings")

  # Load gem defaults via Ace::Support::Config
  # Use centralized gem_root from Nav module (avoids path depth duplication)
  resolver = Ace::Support::Config.create(
    config_dir: ".ace",
    defaults_dir: ".ace-defaults",
    gem_path: Ace::Support::Nav.gem_root
  )

  # Get gem defaults first - uses "nav" namespace for backward compatibility
  gem_defaults = begin
    resolver.resolve_namespace("nav").data
  rescue Ace::Support::Config::YamlParseError => e
    warn "Warning: Failed to parse nav config: #{e.message}" if debug?
    load_gem_defaults_only
  rescue => e
    warn "Warning: Could not load ace-support-nav config: #{e.message}" if debug?
    load_gem_defaults_only
  end

  # Load user config from @config_dir if explicitly set (for testing/override)
  # or use the cascade from resolver
  user_config = if @config_dir
    load_user_config_from_dir(@config_dir)
  else
    # No explicit config_dir - defaults already include cascade
    {}
  end

  # Deep merge: user config over gem defaults
  @configs["settings"] = Ace::Support::Config::Atoms::DeepMerger.merge(gem_defaults, user_config)
end

#protocol_type(protocol_name) ⇒ String

Get the type of a protocol (cmd or file)

Parameters:

  • protocol_name (String)

    The protocol name (e.g., “task”, “wfi”)

Returns:

  • (String)

    Protocol type: “cmd” for command delegation, “file” for file-based (default)



142
143
144
145
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 142

def protocol_type(protocol_name)
  protocol_config = load_protocol_config(protocol_name)
  protocol_config["type"] || "file"
end

#sources_for_protocol(protocol) ⇒ Object

Get sources for a specific protocol



135
136
137
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 135

def sources_for_protocol(protocol)
  @source_registry.sources_for_protocol(protocol)
end

#valid_protocol?(protocol) ⇒ Boolean

Check if a protocol is valid

Returns:

  • (Boolean)


116
117
118
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 116

def valid_protocol?(protocol)
  valid_protocols.include?(protocol)
end

#valid_protocolsObject

Get list of valid protocol names



111
112
113
# File 'lib/ace/support/nav/molecules/config_loader.rb', line 111

def valid_protocols
  load_protocols.keys
end