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
- Install at least one plugin from a marketplace so the store is populated.
- 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/.
- Run
droid plugin marketplace list. It reports no marketplaces.
- Run
droid plugin update <plugin>@<marketplace>. It fails with
Marketplace "<marketplace>" not found.
- 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, ...]}}).
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, anddroid plugin updatereadthe aggregate files
~/.factory/plugins/known_marketplaces.jsonand~/.factory/plugins/installed_plugins.json. Other code paths migrate those aggregatesinto per-record files under
known_marketplaces/andinstalled_plugins/and renamethe aggregate to
*.migrated. After that migration the reading commands report emptyor "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
At the same time, on disk:
Both marketplaces were also correctly declared in
~/.factory/settings.jsonunderextraKnownMarketplaces, withenabledPluginsnaming all three plugins. Sessionsloaded 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
droid plugin marketplace add <url>and letting the store rewrite itself. Confirm that
~/.factory/plugins/known_marketplaces.jsonhas been renamed to.migratedwhileper-record files exist under
known_marketplaces/.droid plugin marketplace list. It reports no marketplaces.droid plugin update <plugin>@<marketplace>. It fails withMarketplace "<marketplace>" not found.known_marketplaces.jsonas a map of marketplace name to entry, rebuiltfrom the per-record files. The commands work again until the next mutation.
Contributing factor: stale mutation locks
Two lock directories persisted after failed mutations:
Their
owner.jsonnamed PIDs that were no longer running. While they existed, themarketplace 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 addfor an already-declared marketplace silently reinstalledtwo unrelated plugins into new cache directories. Additionally,
droid plugin listreports 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
a8e0b49while the cached clone was at15cc055, which we verified withgit loginside the plugin cache.Workaround
Rebuild the aggregates from the per-record files, which are authoritative, and clear
stale
.pendinglocks whose owning PIDs are dead. We automated this as a small scriptthat reads every file in
known_marketplaces/andinstalled_plugins/and writesknown_marketplaces.json(name to entry map) andinstalled_plugins.json(
{"schemaVersion": 1, "plugins": {pluginId: [entry, ...]}}).