appydave-tools 0.35.0 → 0.37.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.
@@ -25,7 +25,13 @@ module Appydave
25
25
 
26
26
  def register(key, klass)
27
27
  @configurations ||= {}
28
- @configurations[key] = klass.new
28
+ # Only create new instance if not already registered (prevents multiple reloads)
29
+ @configurations[key] ||= klass.new
30
+ end
31
+
32
+ # Reset all configurations (primarily for testing)
33
+ def reset
34
+ @configurations = nil
29
35
  end
30
36
 
31
37
  def method_missing(method_name, *_args)
@@ -10,10 +10,27 @@ module Appydave
10
10
  def get_brand(brand_key)
11
11
  brand_key_str = brand_key.to_s
12
12
 
13
+ log.info "Looking up brand: '#{brand_key_str}'" if debug_mode?
14
+
15
+ # Validate data structure
16
+ unless data.is_a?(Hash)
17
+ log.error "Config data is not a Hash: #{data.class}"
18
+ raise "Invalid brands config: data is #{data.class}, expected Hash"
19
+ end
20
+
21
+ unless data['brands'].is_a?(Hash)
22
+ log.error "Config data['brands'] is #{data['brands'].class}, expected Hash"
23
+ log.error "Available keys in data: #{data.keys.inspect}"
24
+ raise "Invalid brands config: 'brands' key is #{data['brands'].class}, expected Hash"
25
+ end
26
+
27
+ log.info "Available brands: #{data['brands'].keys.inspect}" if debug_mode?
28
+
13
29
  # Try direct key lookup first (case-insensitive)
14
30
  brand_entry = data['brands'].find { |key, _info| key.downcase == brand_key_str.downcase }
15
31
  if brand_entry
16
32
  actual_key = brand_entry[0]
33
+ log.info "Found brand by key: '#{actual_key}'" if debug_mode?
17
34
  return BrandInfo.new(actual_key, brand_entry[1])
18
35
  end
19
36
 
@@ -21,10 +38,12 @@ module Appydave
21
38
  brand_entry = data['brands'].find { |_key, info| info['shortcut']&.downcase == brand_key_str.downcase }
22
39
  if brand_entry
23
40
  actual_key = brand_entry[0]
41
+ log.info "Found brand by shortcut: '#{actual_key}'" if debug_mode?
24
42
  return BrandInfo.new(actual_key, brand_entry[1])
25
43
  end
26
44
 
27
45
  # Return default if not found (use normalized lowercase key)
46
+ log.warn "Brand not found: '#{brand_key_str}', returning default" if debug_mode?
28
47
  BrandInfo.new(brand_key_str.downcase, default_brand_info)
29
48
  end
30
49
 
@@ -30,11 +30,31 @@ module Appydave
30
30
  end
31
31
 
32
32
  def load
33
- return JSON.parse(File.read(config_path)) if File.exist?(config_path)
33
+ if debug_mode?
34
+ log.info "Loading config: #{config_name}"
35
+ log.info "Config path: #{config_path}"
36
+ log.info "File exists: #{File.exist?(config_path)}"
37
+ end
38
+
39
+ unless File.exist?(config_path)
40
+ log.warn "Config file not found: #{config_path}" if debug_mode?
41
+ return default_data
42
+ end
34
43
 
44
+ content = File.read(config_path)
45
+ log.info "Config file size: #{content.bytesize} bytes" if debug_mode?
46
+
47
+ data = JSON.parse(content)
48
+ log.info "Config loaded successfully: #{config_name}" if debug_mode?
49
+ log.json data if debug_mode?
50
+ data
51
+ rescue JSON::ParserError => e
52
+ log.error "JSON parse error in #{config_path}: #{e.message}"
53
+ log.error "File content preview: #{content[0..200]}" if content
35
54
  default_data
36
- rescue JSON::ParserError
37
- # log.exception e
55
+ rescue StandardError => e
56
+ log.error "Error loading #{config_path}: #{e.message}"
57
+ log.error e.backtrace.first(3).join("\n") if debug_mode?
38
58
  default_data
39
59
  end
40
60
 
@@ -55,6 +75,10 @@ module Appydave
55
75
 
56
76
  private
57
77
 
78
+ def debug_mode?
79
+ ENV['DAM_DEBUG'] == 'true' || ENV['DEBUG'] == 'true'
80
+ end
81
+
58
82
  def default_data
59
83
  {}
60
84
  end
@@ -109,22 +109,24 @@ module Appydave
109
109
  end
110
110
 
111
111
  # Detect brand and project from current directory
112
- # @return [Array<String, String>] [brand, project] or [nil, nil]
112
+ # @return [Array<String, String>] [brand_key, project] or [nil, nil]
113
113
  def detect_from_pwd
114
114
  current = Dir.pwd
115
115
 
116
116
  # Check if we're inside a v-* directory
117
117
  if current =~ %r{/(v-[^/]+)/([^/]+)/?}
118
- brand = ::Regexp.last_match(1)
119
- project = ::Regexp.last_match(2)
120
- return [brand, project] if project_exists?(brand, project)
118
+ brand_with_prefix = ::Regexp.last_match(1)
119
+ project = ::Regexp.last_match(2) # Capture BEFORE .sub() which resets Regexp.last_match
120
+ # Strip 'v-' prefix to get brand key (e.g., 'v-supportsignal' → 'supportsignal')
121
+ brand_key = brand_with_prefix.sub(/^v-/, '')
122
+ return [brand_key, project] if project_exists?(brand_key, project)
121
123
  end
122
124
 
123
125
  [nil, nil]
124
126
  end
125
127
 
126
128
  # Check if project exists in brand directory
127
- # @param brand [String] Brand name (v-appydave format)
129
+ # @param brand [String] Brand key (e.g., 'appydave', 'supportsignal')
128
130
  # @param project [String] Project name
129
131
  # @return [Boolean] true if project directory exists
130
132
  def project_exists?(brand, project)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.35.0'
5
+ VERSION = '0.37.0'
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.35.0
4
+ version: 0.37.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
@@ -228,6 +228,8 @@ files:
228
228
  - bin/youtube_automation.rb
229
229
  - bin/youtube_manager.rb
230
230
  - docs/README.md
231
+ - docs/ai-instructions/code-quality-retrospective.md
232
+ - docs/ai-instructions/defensive-logging-audit.md
231
233
  - docs/architecture/cli/cli-pattern-comparison.md
232
234
  - docs/architecture/cli/cli-patterns.md
233
235
  - docs/architecture/configuration/configuration-systems.md