Class: Aidp::Metadata::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/metadata/cache.rb

Overview

Manages cached tool directory with automatic invalidation

Loads compiled tool directory from cache, checks for file changes, and regenerates cache when needed.

Examples:

Loading from cache

cache = Cache.new(
  cache_path: ".aidp/cache/tool_directory.json",
  directories: [".aidp/skills", ".aidp/templates"]
)
directory = cache.load

Constant Summary collapse

DEFAULT_TTL =

Default cache TTL (24 hours)

86400

Instance Method Summary collapse

Constructor Details

#initialize(cache_path:, directories: [], ttl: DEFAULT_TTL, strict: false) ⇒ Cache

Initialize cache

Parameters:

  • cache_path (String)

    Path to cache file

  • directories (Array<String>) (defaults to: [])

    Directories to monitor

  • ttl (Integer) (defaults to: DEFAULT_TTL)

    Cache TTL in seconds (default: 24 hours)

  • strict (Boolean) (defaults to: false)

    Whether to fail on validation errors



32
33
34
35
36
37
38
# File 'lib/aidp/metadata/cache.rb', line 32

def initialize(cache_path:, directories: [], ttl: DEFAULT_TTL, strict: false)
  @cache_path = cache_path
  @directories = Array(directories)
  @ttl = ttl
  @strict = strict
  @file_hashes_path = "#{cache_path}.hashes"
end

Instance Method Details

#cache_expired?Boolean

Check if cache has expired based on TTL

Returns:

  • (Boolean)

    True if cache is expired



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/aidp/metadata/cache.rb', line 93

def cache_expired?
  return true unless File.exist?(@cache_path)

  cache_age = Time.now - File.mtime(@cache_path)
  expired = cache_age > @ttl

  if expired
    Aidp.log_debug(
      "metadata",
      "Cache expired",
      age_seconds: cache_age.to_i,
      ttl: @ttl
    )
  end

  expired
end

#cache_valid?Boolean

Check if cache is valid

Returns:

  • (Boolean)

    True if cache exists and is not stale



82
83
84
85
86
87
88
# File 'lib/aidp/metadata/cache.rb', line 82

def cache_valid?
  return false unless File.exist?(@cache_path)
  return false if cache_expired?
  return false if files_changed?

  true
end

#compute_current_hashesHash<String, String>

Compute current file hashes for all source files

Returns:

  • (Hash<String, String>)

    Map of file_path => file_hash



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/aidp/metadata/cache.rb', line 156

def compute_current_hashes
  hashes = {}

  @directories.each do |dir|
    next unless Dir.exist?(dir)

    scanner = Scanner.new([dir])
    md_files = scanner.find_markdown_files(dir)

    md_files.each do |file_path|
      content = File.read(file_path, encoding: "UTF-8")
      hashes[file_path] = Parser.compute_file_hash(content)
    end
  end

  hashes
end

#files_changed?Boolean

Check if source files have changed

Returns:

  • (Boolean)

    True if any source files have changed



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/aidp/metadata/cache.rb', line 114

def files_changed?
  previous_hashes = load_file_hashes
  current_hashes = compute_current_hashes

  changed = previous_hashes != current_hashes

  if changed
    Aidp.log_debug(
      "metadata",
      "Source files changed",
      previous_count: previous_hashes.size,
      current_count: current_hashes.size
    )
  end

  changed
end

#loadHash

Load tool directory from cache or regenerate

Returns:

  • (Hash)

    Tool directory structure



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/aidp/metadata/cache.rb', line 43

def load
  Aidp.log_debug("metadata", "Loading cache", path: @cache_path)

  if cache_valid?
    Aidp.log_debug("metadata", "Using cached directory")
    load_from_cache
  else
    Aidp.log_info("metadata", "Cache invalid, regenerating")
    regenerate
  end
end

#load_file_hashesHash<String, String>

Load saved file hashes

Returns:

  • (Hash<String, String>)

    Saved file hashes



177
178
179
180
181
182
183
184
185
# File 'lib/aidp/metadata/cache.rb', line 177

def load_file_hashes
  return {} unless File.exist?(@file_hashes_path)

  content = File.read(@file_hashes_path, encoding: "UTF-8")
  JSON.parse(content)
rescue JSON::ParserError
  Aidp.log_warn("metadata", "Invalid file hashes cache, regenerating")
  {}
end

#load_from_cacheHash

Load directory from cache file

Returns:

  • (Hash)

    Cached directory structure

Raises:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/aidp/metadata/cache.rb', line 136

def load_from_cache
  content = File.read(@cache_path, encoding: "UTF-8")
  directory = JSON.parse(content)

  Aidp.log_debug(
    "metadata",
    "Loaded from cache",
    tools: directory["statistics"]["total_tools"],
    compiled_at: directory["compiled_at"]
  )

  directory
rescue JSON::ParserError => e
  Aidp.log_error("metadata", "Invalid cache JSON", error: e.message)
  raise Aidp::Errors::ConfigurationError, "Invalid tool directory cache: #{e.message}"
end

#regenerateHash

Regenerate cache from source files

Returns:

  • (Hash)

    Tool directory structure



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/aidp/metadata/cache.rb', line 58

def regenerate
  Aidp.log_info("metadata", "Regenerating tool directory", directories: @directories)

  # Compile directory
  compiler = Compiler.new(directories: @directories, strict: @strict)
  directory = compiler.compile(output_path: @cache_path)

  # Save file hashes for change detection
  save_file_hashes

  directory
end

#reloadHash

Force reload cache

Returns:

  • (Hash)

    Tool directory structure



74
75
76
77
# File 'lib/aidp/metadata/cache.rb', line 74

def reload
  Aidp.log_info("metadata", "Force reloading cache")
  regenerate
end

#save_file_hashesObject

Save current file hashes



188
189
190
191
192
193
194
195
196
197
198
# File 'lib/aidp/metadata/cache.rb', line 188

def save_file_hashes
  hashes = compute_current_hashes

  # Ensure directory exists
  dir = File.dirname(@file_hashes_path)
  FileUtils.mkdir_p(dir) unless Dir.exist?(dir)

  File.write(@file_hashes_path, JSON.pretty_generate(hashes))

  Aidp.log_debug("metadata", "Saved file hashes", count: hashes.size, path: @file_hashes_path)
end