fix: keep the inventory outside the version-pinned plugin directory (0.3.3) - #2
Merged
Merged
Conversation
_fleet-lib.sh derived FM_CONTEXT from its own location. Claude Code installs
the plugin into a version-pinned cache path, so that resolved to something
like .../cache/fleet-manager/fleet-manager/0.3.2/context. Every plugin update
creates a fresh directory: the new version starts with an empty inventory and
the previous server profiles, active-server and inventory.md are stranded
where nothing reads them.
The default is now ${XDG_CONFIG_HOME:-~/.config}/fleet-manager. FM_CONTEXT_DIR
keeps working as the override, so every existing test is unaffected.
A guarded one-time migration copies a pre-0.3.3 in-plugin inventory forward.
It requires real profiles in the legacy directory and none in the new one, so
it cannot clobber a live inventory, and it copies rather than moves.
README and .gitignore claimed the old layout "survives plugin update"; both
now describe where state actually lives.
shellcheck SC2015 flagged six occurrences: with `A && B || C` the C branch also runs when A is true but B fails, so a single check could report both a pass and a fail. assert_exists/assert_absent spell out the if-then-else.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
_fleet-lib.shderivedFM_CONTEXTfrom its own location:Claude Code installs plugins into a version-pinned cache path, so on a real install that resolves to:
Every
claude plugin updatecreates a new directory. The updated plugin starts with an empty inventory, and the previous version's server profiles,active-serverandinventory.mdare stranded where nothing reads them. Both directories are already sitting side by side on a machine that has only ever run 0.3.1 → 0.3.2:Silent data loss on a routine update, and the failure mode is confusing:
/list-serversreports an empty fleet with no error.README.mdand.gitignoreboth claimed this layout "survivesclaude plugin update". It never did.The fix
Default is now
${XDG_CONFIG_HOME:-~/.config}/fleet-manager.FM_CONTEXT_DIRstill overrides, so all 19 existing test call sites are unaffected.A guarded one-time migration copies a pre-0.3.3 inventory forward. It fires only when the legacy directory holds real profiles and the new one holds none, so it cannot clobber a live inventory, and it copies rather than moves — the originals stay in the old cache directory until the next update discards it.
Verification
tests/unit/test-context-dir.sh, 11 assertions, all passing. It stages a fake version-pinned tree (.../0.3.2/commands/_fleet-lib.sh) and sources the real library from it:$HOME/.configfallbackactive-server, skips*.md.template, keeps originalsFM_CONTEXT_DIRRest of the suite unchanged:
test-fleet-lib51/51,test-transfer-lib14/14,test-health-line3/3, static checks OK,claude plugin validatepasses.test-compose-libshows its usual 2 failures locally for want ofdocker/jq; they pass in CI.Note
The
/first-runintake agent declaresAskUserQuestionin its frontmatter but was dispatched without it, so it cannot ask its intake questions and aborts at the first prompt. Out of scope here — filing separately.