Conversation
PR SummaryEnhances plugin installation to resolve nested plugin paths via manifest or recursive search, skips validation in dry-run for non-directory marketplaces, improves error messaging, and adds tests for nested scenarios.
Written by Cursor Bugbot for commit ec947ee. This will update automatically on new commits. Configure here. |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a manifest-aware plugin path resolution flow (new Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as plugin-install
participant FS as filesystem/marketplace
participant Resolver as resolvePluginPath
participant Validator as plugin validator
CLI->>FS: (cond) Load marketplace manifest
note right of CLI: skip manifest if dry-run and\nmarketplace is directory-based
CLI->>Resolver: resolvePluginPath(marketplacePath, pluginName, manifest?)
Resolver->>FS: if manifest path provided -> check manifest source path exists
alt manifest source valid
FS-->>Resolver: manifest source path
else manifest missing/invalid
Resolver->>FS: getAvailablePlugins(...) recursive search
FS-->>Resolver: list of plugin paths
Resolver->>Resolver: match by name or last path segment
alt matched
Resolver-->>CLI: resolved pluginPath
else no match
Resolver-->>CLI: fallback derived path (getPluginSourcePath)
end
end
CLI->>FS: check resolved pluginPath exists (runtime file check)
alt path missing
FS-->>CLI: throw error (includes checked path + nested-dir guidance)
else path exists
CLI->>Validator: validate plugin structure (only if not skipping validation)
alt valid
Validator-->>CLI: ok -> proceed enable/sync (unless dry-run)
else invalid
Validator-->>CLI: standardized "Invalid plugin" error
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
tests/commands/plugin-install.test.ts (1)
435-603: Nested directory tests align well with the new resolution logicThe three tests here do a good job exercising the new behavior: simple nested install, manifest with a bad
sourcestill succeeding via recursive discovery, and multiple nested plugins sharing a base name.One thing to be aware of: in the “multiple nested plugins with same base name” case you only assert that
my-plugin@localis enabled, not which of the two variants was picked. That keeps the behavior intentionally unspecified and dependent on filesystem traversal order. If you ever want deterministic selection (e.g., prefer a specific category or a sorted path), you may want to either codify that inresolvePluginPathor strengthen this test to assert the chosen path/version.src/helpers/marketplace.ts (1)
92-193: resolvePluginPath + recursive discovery correctly handle nested and mis-declared pluginsThe new resolution flow looks solid:
resolvePluginPathnow prefers the manifestsourcewhen it exists and the path is present, but crucially falls back to recursive discovery when the manifest path is missing or when no manifest exists. This directly fixes the earlier issue where a bad manifestsourceprevented discovery of the real plugin location.findPluginsRecursivelyis defensive:
- realpath-based canonicalization plus the
startsWith(canonicalRoot + sep)checks prevent escaping the marketplace root.- the
visitedset stops symlink-driven cycles.- hidden directories are skipped, so
.claude-pluginitself isn’t traversed.- Using
getAvailablePlugins(marketplacePath, null)insideresolvePluginPathintentionally ignores any manifest when doing the fallback search, which is what you want when the manifest may itself be wrong.If you ever notice performance issues on very large marketplace trees, one micro-optimization would be to compute the canonical marketplace root once and thread it through instead of calling
realpath(marketplaceRoot)on every recursion, but that’s not necessary for correctness.Also applies to: 203-216, 218-255
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/commands/plugin-install.ts(3 hunks)src/errors.ts(1 hunks)src/helpers/marketplace.ts(1 hunks)tests/commands/plugin-install.test.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/helpers/marketplace.ts (2)
src/schema.ts (1)
MarketplaceManifest(98-98)src/helpers/fs.ts (1)
fileExists(26-33)
tests/commands/plugin-install.test.ts (2)
src/commands/plugin-install.ts (1)
pluginInstall(22-135)src/helpers/fs.ts (1)
fileExists(26-33)
src/commands/plugin-install.ts (3)
src/helpers/marketplace.ts (3)
loadMarketplaceManifest(71-79)getMarketplaceType(13-15)resolvePluginPath(230-256)src/helpers/fs.ts (1)
fileExists(26-33)src/helpers/io.ts (1)
defaultIO(79-79)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (2)
src/errors.ts (1)
9-16: More precise PluginManifestNotFoundError message looks goodIncluding
${pluginPath}/.claude-plugin/plugin.jsonin the error text makes it much clearer what concrete path was expected for the manifest, especially now that plugins can live in nested directories. No issues here.src/commands/plugin-install.ts (1)
10-11: Dry-run gating and plugin path resolution look correct and address prior issues
- The
shouldSkipValidationflag (cmd.dryRun && marketplace.source !== 'directory') cleanly restores the old behavior for git/url marketplaces in dry-run: you still resolve the marketplace path, but you no longer attempt to load a manifest, resolve a plugin path, or validate structure against an uncached checkout before the dry-run early return. Directory-based marketplaces are still validated, which matches local expectations.- The new flow:
- loads the appropriate manifest via
loadMarketplaceManifest(marketplacePath, getMarketplaceType(marketplaceName)),- resolves
pluginPaththroughresolvePluginPath(manifest first, then recursive search, then fallback),- and only then checks
fileExists(pluginPath)with a helpful error message that includes the checked path and hints about nested directories.
This aligns with the new nested-directory tests.- The post-install guard
is a good defensive check and is indeed unreachable under the current control flow, since any non-dry-run path always setsif (!pluginPath) { throw new Error(`Plugin path not resolved for '${pluginName}'`); }pluginPathor throws earlier.Overall, the changes here tie together the new marketplace helper logic and dry-run semantics without introducing new edge-case regressions.
Also applies to: 63-76, 77-95, 118-122
No description provided.