-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add APM CLI - init, install, compile, deps #271
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull Request Overview
This pull request introduces comprehensive APM (Agent Package Manager) functionality into the project, adding a new CLI subcommand system for managing modular context packages and files. The PR implements a complete APM ecosystem including dependency management, context compilation, and package discovery.
Key Changes:
- Added complete APM CLI integration with
specify apm
subcommands (init, install, compile, deps) - Implemented distributed context compilation system with optimization engine
- Added GitHub package downloader with authentication and dependency resolution
- Enhanced
specify init
to include APM scaffolding setup
Reviewed Changes
Copilot reviewed 64 out of 64 changed files in this pull request and generated 4 comments.
File | Description |
---|---|
src/specify_cli/init.py | Main CLI integration adding APM subcommands and wrapper functions |
templates/apm/hello-world/apm.yml | Template configuration file with project metadata and dependencies |
src/apm_cli/ | Complete APM CLI implementation with workflow, registry, deps, and compilation modules |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
self.adapter = ClientFactory.create_client(runtime) | ||
self.conflict_detector = MCPConflictDetector(self.adapter) | ||
|
||
def install_servers(self, server_references: List[str], env_overrides: Dict[str, str] = None, server_info_cache: Dict[str, Any] = None, runtime_vars: Dict[str, str] = None) -> InstallationSummary: |
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.
Method signature has too many optional parameters with mutable defaults. Consider using Optional[Dict[str, str]] instead of Dict[str, str] = None for type safety, and consider grouping related parameters into a configuration object.
Copilot uses AI. Check for mistakes.
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.
Would postpone for later due to breadth of changes needed
…s (APM packages with same repo name different owner are now handled well)
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.
Pull Request Overview
Copilot reviewed 64 out of 65 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
original_argv = sys.argv.copy() | ||
try: | ||
sys.argv = ["apm"] + args | ||
try: | ||
apm_click.main(args, standalone_mode=False) | ||
except SystemExit as e: | ||
if e.code != 0: | ||
raise typer.Exit(e.code) | ||
finally: | ||
sys.argv = original_argv |
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.
Modifying sys.argv
globally is a risky pattern that could cause issues in concurrent environments or testing. Consider using Click's context passing or subprocess execution for better isolation.
original_argv = sys.argv.copy() | |
try: | |
sys.argv = ["apm"] + args | |
try: | |
apm_click.main(args, standalone_mode=False) | |
except SystemExit as e: | |
if e.code != 0: | |
raise typer.Exit(e.code) | |
finally: | |
sys.argv = original_argv | |
try: | |
apm_click.main(args, standalone_mode=False) | |
except SystemExit as e: | |
if e.code != 0: | |
raise typer.Exit(e.code) |
Copilot uses AI. Check for mistakes.
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.
High effort and no easy way to do this without breaking either output formatting, argument passing, etc
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.
Pull Request Overview
Copilot reviewed 65 out of 66 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
# Use GitHub Enterprise x-access-token format for authenticated access | ||
# This is the standard format for GitHub Actions and Enterprise environments | ||
return f"https://x-access-token:{self.github_token}@github.com/{repo_ref}.git" |
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.
The GitHub token is being embedded directly in the URL, which could be logged or exposed in error messages. Consider using Git credential helpers or environment variables that Git can access securely instead of embedding tokens in URLs.
Copilot uses AI. Check for mistakes.
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.
The code already implements some security measures:
- Error Sanitization: The _sanitize_git_error() method specifically removes tokens from error messages using regex patterns
- Environment Control: The code sets GIT_TERMINAL_PROMPT='0' and GIT_ASKPASS='echo' to prevent interactive prompts
Alternative auth methods had been explored but complex to implement in headless / non-interactive scripts. I'd rather go for the simple approach with the above mitigation as phase 1.
Co-authored-by: Copilot <[email protected]>
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.
Pull Request Overview
Copilot reviewed 65 out of 66 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/apm_cli/deps/github_downloader.py:1
- The urllib.parse import should be moved to the top of the file with other imports rather than being imported within a method for better code organization and to avoid repeated imports.
"""GitHub package downloader for APM dependencies."""
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
def _get_available_tokens(self, env: Dict[str, str]) -> Dict[str, str]: | ||
"""Get all available GitHub tokens from environment.""" | ||
tokens = {} | ||
for purpose, token_vars in self.TOKEN_PRECEDENCE.items(): | ||
for token_var in token_vars: | ||
if token_var in env and env[token_var]: | ||
tokens[token_var] = env[token_var] | ||
return tokens |
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.
This method returns a flat dictionary of token variables, but it's designed to return available tokens by purpose. The method should return Dict[str, Optional[str]] mapping purposes to their best available tokens, not all token variables.
Copilot uses AI. Check for mistakes.
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.
This would mean a complex re-architecture of auth mechanisms, so I'd leave this for later
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.
Pull Request Overview
Copilot reviewed 65 out of 66 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/apm_cli/deps/github_downloader.py:1
- The hostname validation should use case-insensitive comparison since hostnames are case-insensitive. Use
parsed_url.netloc.lower() != 'github.com'
to prevent bypass with different casing.
"""GitHub package downloader for APM dependencies."""
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
def _extract_directories_from_pattern(self, pattern: str) -> List[Path]: | ||
"""Extract potential directory paths from a file pattern. | ||
Args: | ||
pattern (str): File pattern like "src/**/*.py" or "docs/*.md" | ||
Returns: | ||
List[Path]: List of directory paths that could contain matching files. | ||
""" |
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.
This method is called for every instruction during directory analysis. Consider caching results since patterns are likely to be repeated across instructions, especially for common patterns like **/*.py
.
Copilot uses AI. Check for mistakes.
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.
Good improvement but not in scope for this PR
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
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.
Pull Request Overview
Copilot reviewed 65 out of 66 changed files in this pull request and generated 6 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
… sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
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.
Pull Request Overview
Copilot reviewed 65 out of 66 changed files in this pull request and generated 5 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
@localden ready for your review |
This pull request introduces APM (Agent Package Manager) integration into the project, providing new functionality for managing modular context packages and files. It adds a new
apm
subcommand to the CLI, updates README.md to reflect these changes, and brings in a set of new dependencies and Python modules to support APM features.specify init
modified to also add basic apm scaffolding (apm.yml
)specify apm install
to install APM modules fromapm.yml
specify apm compile
to trigger the context compiler and generated optimal nestedagents.md
filesspecify apm deps
for operations related to APM module dependencies