One embedded skill. The text ships inside the binary, so every upgrade
path — brew, cargo, bb update — carries new content as an inherent
consequence rather than needing a separate sync. It also means an installed
skill can never describe a flag this binary lacks.
Whether refresh_tracked should recreate an entry whose file has been
deleted. Explicit bb skill install/bb update pass Restore, because a
human asked for it there; the auto-refresh that runs before every command
passes Preserve, because a deliberately deleted skill file must not be
silently written back into a user’s working tree.
Distinguishes why an entry did not end up removed, so the caller can be
honest about it instead of collapsing “refused because modified” and
“wasn’t there to begin with” into the same boolean.
Entries plus an optional warning. A missing state file simply means nothing
is tracked; a corrupt one is reported but treated as empty, so a hand-edited
file cannot brick bb update.
Refreshes every tracked entry against the currently-running binary’s
embedded text. Driven by the recorded entries rather than a root and an
agent list, so a single call spans every project the user has installed
into. Uses the same drift rules as install, via state_of: Stale
rewrites the file and updates the recorded hash, Modified is left
byte-identical and reported as SkippedModified, and Current is
reported as Unchanged without touching anything. Missing is rewritten
only under MissingPolicy::Restore — Preserve (what the pre-command
auto-refresh passes) leaves a deliberately deleted file deleted, reporting
nothing and leaving the entry’s version untouched so it is not mistaken
for current.
Writes via a temp file in the same directory plus rename, so two bb
processes racing right after an upgrade cannot interleave and leave a
truncated skills.json — fs::write truncates first, and rename on the
same filesystem is atomic where plain writes are not.
True when any tracked entry was written by a different build than the one
running now. This is the whole auto-refresh trigger: a string compare over a
handful of entries, so the common case — everything current — costs nothing
beyond reading the state file.