Packages

fnord

0.9.38

AI code archaeology

Current section

Files

Jump to
fnord lib store project entry metadata.ex
Raw

lib/store/project/entry/metadata.ex

defmodule Store.Project.Entry.Metadata do
defstruct [:store_path, :source_file]
@filename "metadata.json"
@behaviour Store.Project.EntryFile
@impl Store.Project.EntryFile
def new(entry_path, source_file) do
%__MODULE__{
store_path: Path.join(entry_path, @filename),
source_file: source_file
}
end
@impl Store.Project.EntryFile
def exists?(file), do: file |> store_path() |> File.exists?()
@impl Store.Project.EntryFile
def store_path(file), do: file.store_path
@impl Store.Project.EntryFile
def read(file) do
file.store_path
|> File.read()
|> case do
{:ok, contents} -> SafeJson.decode(contents)
error -> error
end
end
@impl Store.Project.EntryFile
def write(file, data \\ %{}) do
data = if is_map(data), do: data, else: %{}
rel_path = Map.get(data, :rel_path) || Map.get(data, "rel_path")
# Callers that know the content hash upfront (git mode passes the blob
# SHA straight through from ls-tree) should set `hash:` in `data`.
# Otherwise we fall back to hashing the working-tree file so this
# function remains usable from test / tooling call sites that bypass
# the Source-aware save pipeline.
hash = Map.get(data, :hash) || Map.get(data, "hash") || mkhash(file.source_file)
# `embedding_dim` is recorded here so `is_stale?` can answer the
# "does the stored vector match the current model?" question without
# opening the embeddings file on every scan. Written only when the
# caller has a dim to persist - older stores upgrade lazily on their
# first post-upgrade scan (see Entry.embedding_dim_is_current?/2).
embedding_dim = Map.get(data, :embedding_dim) || Map.get(data, "embedding_dim")
base = %{
file: rel_path || file.source_file,
timestamp: DateTime.utc_now(),
hash: hash
}
payload =
case embedding_dim do
dim when is_integer(dim) -> Map.put(base, :embedding_dim, dim)
_ -> base
end
payload
|> SafeJson.encode()
|> case do
{:ok, json} -> File.write(file.store_path, json)
error -> error
end
end
defp mkhash(file) do
:crypto.hash(:sha256, File.read!(file))
|> Base.encode16(case: :lower)
end
end