Skip to content

Fix: Prevent stray root bower.json from duplicating plugins on install (fixes #235) - #249

Open
swashbuck wants to merge 6 commits into
masterfrom
issue/235
Open

swashbuck wants to merge 6 commits into
masterfrom
issue/235

Conversation

@swashbuck

@swashbuck swashbuck commented Mar 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #235

Fix

  • Install each plugin from an isolated working directory so an ambient (legacy) root bower.json cannot inject its own dependencies into the install directory. This is the actual cause of adapt install places menu plugin in src/components/ when already installed in src/menu/ #235: a stale bower.json ("name": "manifest"), left over from the old grunt/bower toolchain and never removed, pinned adapt-contrib-boxMenu@7.1.0. Bower installed that manifest dependency into whichever type folder the requested plugin used (e.g. src/components when installing adapt-contrib-media), creating a duplicate copy of boxMenu.

Update

  • Skip reinstalling plugins already at the resolved version (projectVersion === matchedVersion), and fetch installed-plugin info during install so that comparison is available. Reduces redundant reinstalls on a no-arg adapt install.

Testing

Setup

  1. Start from a fresh framework project (e.g. 5.56.2) with the default plugins installed (run adapt install once), so adapt-contrib-boxMenu is present in src/menu/.
  2. Add a legacy root bower.json at the project root:
{
    "name": "manifest",
    "dependencies": {
        "adapt-contrib-boxMenu": "7.1.0"
    }
}

Reproduce the bug (current published CLI / master)

  1. Run adapt install adapt-contrib-media.
  2. Observe: adapt-contrib-boxMenu@7.1.0 is duplicated into src/components/, alongside the correct copy still in src/menu/.

Verify the fix (this PR, issue/235)

  1. Delete the duplicate src/components/adapt-contrib-boxMenu, leaving the root bower.json in place.
  2. Run adapt install adapt-contrib-media again.
  3. Confirm adapt-contrib-media installs to src/components/ and adapt-contrib-boxMenu is NOT duplicated there.
  4. Run adapt install (no args) and confirm already-current plugins are skipped rather than reinstalled.

Comment thread lib/integration/Plugin.js Resolved
@oliverfoster oliverfoster moved this from Needs Reviewing to Assigned in adapt_framework: The TODO Board Apr 13, 2026
@swashbuck swashbuck moved this from Assigned to Needs Reviewing in adapt_framework: The TODO Board Apr 13, 2026
@swashbuck swashbuck changed the title Fix: Prevent plugins from being installed to wrong type directory (fixes #235) Fix: Prevent stray root bower.json from duplicating plugins on install (fixes #235) Jun 4, 2026
@swashbuck

Copy link
Copy Markdown
Contributor Author

@oliverfoster

Dug into the actual cause rather than working around it. It's not type detection: boxMenu's metadata already resolves to menu correctly. The duplicate comes from a stale legacy root bower.json ("name": "manifest") left over from the old grunt/bower toolchain. On any install the CLI hands bower the target's type folder as directory plus the project cwd, and bower installs that manifest's pinned deps into the same folder, so adapt install adapt-contrib-media drops the manifest's adapt-contrib-boxMenu@7.1.0 into src/components. Reproduced by adding that file to a clean project; the duplicate disappears when it's removed.

Changes off the back of that:

  • Dropped the path-based type inference. You were right, it was redundant given metadata already resolves the type.
  • Fix: run bower install from an isolated working dir so an ambient bower.json can't inject its deps. The project .bowerrc is copied across so registry/proxy/etc stay intact. ~20 lines confined to the two bower call sites, and it goes away entirely with the npm move.

Verified the install and update paths against a project carrying the stale manifest: the requested plugin installs correctly, no duplicate, .bowerrc settings preserved.

One open call: the PR also skips reinstalling plugins already at the resolved version (less redundant work on a no-arg adapt install). Happy to split that into its own PR if you'd rather keep this focused purely on #235.

Posted via collaboration with Claude Code

@swashbuck
swashbuck requested a review from oliverfoster June 4, 2026 22:25

@oliverfoster oliverfoster left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested from a framework 5.56.3 project with a legacy root bower.json ("name": "manifest", adapt-contrib-boxMenu: 7.1.0), running bin/adapt.js from each branch:

adapt install adapt-contrib-media
master media installed, plus adapt-contrib-boxMenu 7.1.0 duplicated into src/components/ (7.7.0 still in src/menu/)
this branch media installed, no duplicate, no adapt-cli-* temp dirs left behind

The isolated cwd doesn't affect local-path sources (they're copied from sourcePath), and the framework's .bowerrc "directory": "src/plugins" is overridden by the explicit directory option, so copying it across is safe.

Two things about the skip-when-current change (markInstallable):

  1. Output reads as a failure. When everything is already current, adapt install, and adapt install adapt-contrib-media with media already installed, lists every plugin under "The following plugins were skipped" and ends with "None of the requested plugins could be installed". Something like "already up to date" would be clearer for plugins skipped for this reason.
  2. No way to force a reinstall. Previously adapt install reinstalled a plugin at the same version, which reset local edits. With the skip there's no flag for that (--clean only cleans the bower cache). Could this have a --force, or apply only to no-argument installs so an explicitly named plugin is still reinstalled?

The skip is separate from #235. If it needs more discussion, the isolation fix could go in on its own.

…up to date

A named install now always reinstalls, so it can reset local edits.
Plugins left out for being current are listed as "already up to date"
instead of "skipped", and no longer trigger "None of the requested
plugins could be installed". Local-path and --dev installs are never
skipped. The installed version is read through a separate Plugin so a
target's project info stays unset before install, as on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@swashbuck

Copy link
Copy Markdown
Contributor Author

@oliverfoster Thanks for testing. I've kept the skip and addressed both points in a9e540d, rather than splitting it out. Without the skip, a plain adapt install re-downloads every plugin in adapt.json every time, and your two points were about how the skip behaves, not whether we want it. Dropping it would have left that for another PR to rediscover.

1. Output. Plugins left out because they're current now get their own group:

The following plugins are already up to date:
adapt-contrib-media 7.2.1 (latest compatible version is 7.2.1)
adapt-contrib-boxMenu 7.7.1 (latest compatible version is 7.7.1)
All requested plugins are already up to date

They no longer appear under "skipped". "None of the requested plugins could be installed" only shows when something actually failed or was skipped. --dry-run uses the same grouping.

2. Forcing a reinstall. Went with your second suggestion: the skip only applies to a plain adapt install. A named plugin (adapt install adapt-contrib-media) is always reinstalled, so it still resets local edits, and no new flag is needed. Two more cases are never skipped:

  • Local-path sources, because their version doesn't change when the files are edited.
  • --dev installs, because they replace a registry copy with a git clone.

One other change. The earlier commit read the installed plugin info (fetchProjectInfo) for every target before resolving versions. That changed more than the skip did. For local sources, findCompatibleVersion started matching the installed version instead of the source version. A plugin last installed from a path (_wasInstalledFromPath) also became isLocalSource when installed from the registry, which would send install() down the copy route with no sourcePath. That step is gone. markAlreadyInstalled() now runs after conflict resolution and reads the installed version through a separate Plugin, so everything up to that point behaves as it does on master.

Tested against a 5.56.3 project with the legacy root bower.json (adapt-contrib-boxMenu: 7.1.0) and the framework .bowerrc:

Run Result
adapt install, empty src media and boxMenu installed to the right folders, no duplicate, no adapt-cli-* temp dirs
adapt install again (with a local edit in media) both listed as already up to date, local edit kept
adapt install --dry-run same grouping
adapt install adapt-contrib-media reinstalled, local edit reset
adapt install with boxMenu's installed version set back to 7.0.0 boxMenu updated to 7.7.1, media listed as up to date
adapt install with media in adapt.json as a local path media recopied from the path, boxMenu up to date

Posted via collaboration with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Needs Reviewing

Development

Successfully merging this pull request may close these issues.

adapt install places menu plugin in src/components/ when already installed in src/menu/

2 participants