-
Notifications
You must be signed in to change notification settings - Fork 154
fix(marketplace): add honors manifest.name for Claude Code parity
#1032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |||||||||||||||
| import builtins | ||||||||||||||||
| import json | ||||||||||||||||
| import os | ||||||||||||||||
| import re | ||||||||||||||||
| import subprocess | ||||||||||||||||
| import sys | ||||||||||||||||
| import traceback | ||||||||||||||||
|
|
@@ -44,6 +45,16 @@ | |||||||||||||||
| from ._helpers import _get_console, _is_interactive | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| # Marketplace alias must satisfy this pattern so it can appear on the right of | ||||||||||||||||
| # ``@`` in ``apm install <plugin>@<marketplace>`` syntax. | ||||||||||||||||
| _ALIAS_PATTERN = re.compile(r"^[a-zA-Z0-9._-]+$") | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def _is_valid_alias(value: str) -> bool: | ||||||||||||||||
| """Return True when ``value`` is a legal marketplace alias.""" | ||||||||||||||||
| return bool(value) and _ALIAS_PATTERN.match(value) is not None | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||
| # Custom group for organised --help output | ||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||
|
|
@@ -336,28 +347,22 @@ def add(repo, name, branch, host, verbose): | |||||||||||||||
| resolved_host = normalized_host | ||||||||||||||||
| else: | ||||||||||||||||
| resolved_host = default_host() | ||||||||||||||||
| display_name = name or repo_name | ||||||||||||||||
|
|
||||||||||||||||
| # Validate name is identifier-compatible for NAME@MARKETPLACE syntax | ||||||||||||||||
| import re | ||||||||||||||||
|
|
||||||||||||||||
| if not re.match(r"^[a-zA-Z0-9._-]+$", display_name): | ||||||||||||||||
| # Hard-fail if the user-supplied --name flag is malformed; the | ||||||||||||||||
| # manifest's name is validated softly below (publisher mistakes | ||||||||||||||||
| # shouldn't break a successful add). | ||||||||||||||||
| if name is not None and not _is_valid_alias(name): | ||||||||||||||||
| logger.error( | ||||||||||||||||
| f"Invalid marketplace name: '{display_name}'. " | ||||||||||||||||
| f"Invalid marketplace name: '{name}'. " | ||||||||||||||||
| f"Names must only contain letters, digits, '.', '_', and '-' " | ||||||||||||||||
| f"(required for 'apm install plugin@marketplace' syntax)." | ||||||||||||||||
| ) | ||||||||||||||||
| sys.exit(1) | ||||||||||||||||
|
|
||||||||||||||||
| logger.start(f"Registering marketplace '{display_name}'...", symbol="gear") | ||||||||||||||||
| logger.verbose_detail(f" Repository: {owner}/{repo_name}") | ||||||||||||||||
| logger.verbose_detail(f" Branch: {branch}") | ||||||||||||||||
| if resolved_host != "github.com": | ||||||||||||||||
| logger.verbose_detail(f" Host: {resolved_host}") | ||||||||||||||||
|
|
||||||||||||||||
| # Auto-detect marketplace.json location | ||||||||||||||||
| # Probe for the marketplace.json location. The probe source's name | ||||||||||||||||
| # is a placeholder -- _auto_detect_path only consults host/owner/repo. | ||||||||||||||||
| probe_source = MarketplaceSource( | ||||||||||||||||
| name=display_name, | ||||||||||||||||
| name=name or repo_name, | ||||||||||||||||
| owner=owner, | ||||||||||||||||
| repo=repo_name, | ||||||||||||||||
| branch=branch, | ||||||||||||||||
|
|
@@ -373,9 +378,56 @@ def add(repo, name, branch, host, verbose): | |||||||||||||||
| ) | ||||||||||||||||
| sys.exit(1) | ||||||||||||||||
|
|
||||||||||||||||
| # Fetch and validate the manifest before logging start, so that the | ||||||||||||||||
| # success/start lines display the *final* alias the user must use. | ||||||||||||||||
| fetch_source = MarketplaceSource( | ||||||||||||||||
| name=name or repo_name, | ||||||||||||||||
| owner=owner, | ||||||||||||||||
| repo=repo_name, | ||||||||||||||||
| branch=branch, | ||||||||||||||||
| host=resolved_host, | ||||||||||||||||
| path=detected_path, | ||||||||||||||||
| ) | ||||||||||||||||
| manifest = fetch_marketplace(fetch_source, force_refresh=True) | ||||||||||||||||
| plugin_count = len(manifest.plugins) | ||||||||||||||||
|
|
||||||||||||||||
| # Resolve final alias: --name flag > manifest.name (if valid) > repo name. | ||||||||||||||||
| # Track which tier won so we can report it in verbose mode and emit a | ||||||||||||||||
| # warning when a publisher-declared name had to be rejected. | ||||||||||||||||
| manifest_name = (manifest.name or "").strip() | ||||||||||||||||
| if name is not None: | ||||||||||||||||
|
Comment on lines
+397
to
+398
|
||||||||||||||||
| display_name = name | ||||||||||||||||
| alias_source = "--name flag" | ||||||||||||||||
| elif manifest_name and _is_valid_alias(manifest_name): | ||||||||||||||||
|
Comment on lines
+394
to
+401
|
||||||||||||||||
| display_name = manifest_name | ||||||||||||||||
| alias_source = f"manifest.name ('{manifest_name}')" | ||||||||||||||||
| else: | ||||||||||||||||
| display_name = repo_name | ||||||||||||||||
| if manifest_name and not _is_valid_alias(manifest_name): | ||||||||||||||||
| logger.warning( | ||||||||||||||||
| f"Manifest declares name '{manifest_name}' which is not a " | ||||||||||||||||
| f"valid alias (must match [a-zA-Z0-9._-]+). " | ||||||||||||||||
| f"Falling back to repo name." | ||||||||||||||||
| ) | ||||||||||||||||
| alias_source = f"repo name (manifest.name '{manifest_name}' invalid)" | ||||||||||||||||
|
Comment on lines
+407
to
+412
|
||||||||||||||||
| else: | ||||||||||||||||
| alias_source = "repo name (manifest.name missing)" | ||||||||||||||||
|
|
||||||||||||||||
| # Defense-in-depth: repo names from GitHub already satisfy the alias | ||||||||||||||||
| # regex, so this invariant should always hold by the time we register. | ||||||||||||||||
| assert _is_valid_alias(display_name), ( | ||||||||||||||||
| f"Resolved marketplace alias '{display_name}' failed validation" | ||||||||||||||||
| ) | ||||||||||||||||
|
Comment on lines
+418
to
+420
|
||||||||||||||||
| assert _is_valid_alias(display_name), ( | |
| f"Resolved marketplace alias '{display_name}' failed validation" | |
| ) | |
| if not _is_valid_alias(display_name): | |
| raise click.ClickException( | |
| f"Resolved marketplace alias '{display_name}' failed validation" | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fetch_marketplace()caches bysource.name(seemarketplace/client.py::_cache_key). When the manifest alias differs from the repo name, thisaddpath fetches/caches under the repo name, then registers under the manifest alias, so the nextinstall/browse/searchby alias will miss cache and re-fetch immediately. Consider writing the fetched data to the cache key for the final alias (or changing the cache key to be based on host/owner/repo/path rather than alias) to avoid the extra network call.