Skip to content

Plugin store migration renames the aggregate index that plugin list/marketplace list/plugin update still read #23

Description

@TFluegge89

Product: Droid CLI
Version: 0.157.1
Platform: Windows 10 Enterprise (10.0.26100), PowerShell 5.1
Severity: Medium. Plugin management commands become unusable. Session plugin
loading is unaffected, so the impact is on management and update, not runtime.

Summary

droid plugin list, droid plugin marketplace list, and droid plugin update read
the aggregate files ~/.factory/plugins/known_marketplaces.json and
~/.factory/plugins/installed_plugins.json. Other code paths migrate those aggregates
into per-record files under known_marketplaces/ and installed_plugins/ and rename
the aggregate to *.migrated. After that migration the reading commands report empty
or "not found", even though the per-record files are present and correct.

The result is misleading: the CLI reports that nothing is installed and no marketplace
is registered, while the plugins themselves continue to load and work in sessions.

Observed behavior

> droid plugin marketplace list
No marketplaces registered.

> droid plugin list
No plugins installed.

> droid plugin update internal-agent@internal-plugins
Failed to update : Marketplace "internal-plugins" not found
Error: Some plugins failed to update

> droid plugin marketplace remove factory-plugins
Error: Marketplace "factory-plugins" not found

At the same time, on disk:

~/.factory/plugins/known_marketplaces/factory-plugins-<hash>.json    present, valid
~/.factory/plugins/known_marketplaces/internal-plugins-<hash>.json    present, valid
~/.factory/plugins/installed_plugins/core-factory-plugins-user-<hash>.json          present, valid
~/.factory/plugins/installed_plugins/droid-control-factory-plugins-user-<hash>.json present, valid
~/.factory/plugins/installed_plugins/internal-agent-internal-plugins-user-<hash>.json present, valid

~/.factory/plugins/known_marketplaces.json            MISSING
~/.factory/plugins/known_marketplaces.json.migrated   present
~/.factory/plugins/installed_plugins.json             MISSING (after mutation)
~/.factory/plugins/installed_plugins.json.migrated    present

Both marketplaces were also correctly declared in ~/.factory/settings.json under
extraKnownMarketplaces, with enabledPlugins naming all three plugins. Sessions
loaded the plugins and their skills normally throughout, which is what made the CLI
output misleading rather than merely broken.

Expected behavior

Either the reading commands should read the per-record files after migration, or the
migration should keep the aggregate in sync. A management command should never report
"No plugins installed" while those plugins are installed and loading.

Reproduction

  1. Install at least one plugin from a marketplace so the store is populated.
  2. Trigger the migration, for example by running droid plugin marketplace add <url>
    and letting the store rewrite itself. Confirm that
    ~/.factory/plugins/known_marketplaces.json has been renamed to .migrated while
    per-record files exist under known_marketplaces/.
  3. Run droid plugin marketplace list. It reports no marketplaces.
  4. Run droid plugin update <plugin>@<marketplace>. It fails with
    Marketplace "<marketplace>" not found.
  5. Recreate known_marketplaces.json as a map of marketplace name to entry, rebuilt
    from the per-record files. The commands work again until the next mutation.

Contributing factor: stale mutation locks

Two lock directories persisted after failed mutations:

~/.factory/plugins/.locks/marketplace-mutations.lock.<uuid>.pending/owner.json

Their owner.json named PIDs that were no longer running. While they existed, the
marketplace read path stayed empty even after the aggregate was restored. Removing the
stale locks plus restoring the aggregate fixed listing and update together. Stale locks
whose owning process is gone should be reclaimed automatically.

Also observed

droid plugin marketplace add for an already-declared marketplace silently reinstalled
two unrelated plugins into new cache directories. Additionally, droid plugin list
reports the version as the original cache directory hash rather than the currently
checked-out commit, so a plugin that has been updated in place still displays its
original hash. In our case the label read a8e0b49 while the cached clone was at
15cc055, which we verified with git log inside the plugin cache.

Workaround

Rebuild the aggregates from the per-record files, which are authoritative, and clear
stale .pending locks whose owning PIDs are dead. We automated this as a small script
that reads every file in known_marketplaces/ and installed_plugins/ and writes
known_marketplaces.json (name to entry map) and installed_plugins.json
({"schemaVersion": 1, "plugins": {pluginId: [entry, ...]}}).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions