Repository navigation
feat: add agentify list
#66
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
Open
ycexiao
wants to merge
3
commits into
diffpy:main
Choose a base branch
from
ycexiao:agentify-list
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| **Added:** | ||
|
|
||
| * Add diffpy-app agentify list and support -skill flag for both diffpy-app agentify and diffpy-app agentify list. | ||
|
|
||
| **Changed:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Deprecated:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Removed:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Fixed:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Security:** | ||
|
|
||
| * <news item> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,13 @@ | |
| import subprocess | ||
| import tempfile | ||
| import warnings | ||
| from contextlib import contextmanager | ||
| from pathlib import Path | ||
|
|
||
| from rich.console import Console | ||
| from rich.text import Text | ||
| from rich.theme import Theme | ||
|
|
||
| REPO_URL = "https://github.com/diffpy/cmi-agent-skills" | ||
|
|
||
|
|
||
|
|
@@ -22,48 +27,154 @@ def internet_available(): | |
| return agentify_available | ||
|
|
||
|
|
||
| def agentify(args): | ||
| @contextmanager | ||
| def cloned_skills(): | ||
| """Yield the path of a fresh clone of the skills repo.""" | ||
| if not ensure_setup(): | ||
| raise ValueError( | ||
| "Internet connection or git unavailable. " | ||
| "Please ensure git is installed and you have an active internet " | ||
| f"connection to {REPO_URL}." | ||
| ) | ||
| with tempfile.TemporaryDirectory() as tmp: | ||
| tmp_path = Path(tmp) | ||
| subprocess.run( | ||
| [ | ||
| "git", | ||
| "clone", | ||
| "--depth=1", | ||
| "--filter=blob:none", | ||
| "--sparse", | ||
| REPO_URL, | ||
| str(tmp_path), | ||
| ], | ||
| check=True, | ||
| capture_output=True, | ||
| ) | ||
| subprocess.run( | ||
| [ | ||
| "git", | ||
| "-C", | ||
| str(tmp_path), | ||
| "sparse-checkout", | ||
| "set", | ||
| "--no-cone", | ||
| "/skills.json", | ||
| ], | ||
| check=True, | ||
| capture_output=True, | ||
| ) | ||
| yield tmp_path | ||
|
|
||
|
|
||
| def list_skills(args): | ||
| console = Console( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the same prompt package that cookiecuter and scikit-package use. |
||
| theme=Theme( | ||
| { | ||
| "skill_name": "bold cyan", | ||
| "description": "green", | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| def print_skill(name, skills_brief_dict): | ||
| line = Text(f"{name}: ", style="skill_name") | ||
| if "description" not in skills_brief_dict[name]: | ||
| skills_brief_dict[name][ | ||
| "description" | ||
| ] = "Description not available." | ||
| description = skills_brief_dict[name]["description"] | ||
| line.append(str(description), style="description") | ||
| console.print(line) | ||
|
|
||
| with cloned_skills() as tmp_path: | ||
| skills_brief_dict = json.loads((tmp_path / "skills.json").read_text()) | ||
| if args.requested_skill_names is None: | ||
| # No skills specified, print up to 10 skills | ||
| n_skills_to_show = 10 | ||
| for i, name in enumerate(skills_brief_dict): | ||
| if i >= n_skills_to_show: | ||
| break | ||
| print_skill(name, skills_brief_dict) | ||
| else: | ||
| # skills specified by the user. | ||
| for name in args.requested_skill_names: | ||
| if name not in skills_brief_dict: | ||
| warnings.warn( | ||
| f"Skill '{name}' not found. " | ||
| f"Run 'agentify list' to see available skills." | ||
| ) | ||
| continue | ||
| print_skill(name, skills_brief_dict) | ||
|
|
||
|
|
||
| def agentify(args): | ||
| agent = args.agent | ||
| system_flag = args.system | ||
| # determine destination directory based on the agent and scope | ||
| if agent == "claude": | ||
| skills_dir = ".claude/skills" | ||
| elif agent == "codex": | ||
| skills_dir = ".codex/skills" | ||
| else: | ||
| raise KeyError( | ||
| f"{agent} could not be recognized. " | ||
| "Please use either 'claude' or 'codex'." | ||
| ) | ||
| if system_flag: | ||
| dest_dir = Path().home() / skills_dir | ||
| else: | ||
| dest_dir = Path().cwd() / skills_dir | ||
| with tempfile.TemporaryDirectory() as tmp: | ||
| tmp_path = Path(tmp) | ||
| subprocess.run( | ||
| ["git", "clone", REPO_URL, str(tmp_path)], | ||
| check=True, | ||
| ) | ||
| skills = json.load(open(tmp_path / "skills.json")) | ||
| for item in tmp_path.iterdir(): | ||
| if item.is_dir(): | ||
| destination = dest_dir / item.name | ||
| if item.name not in skills: | ||
| continue | ||
| if destination.exists(): | ||
| if args.update: | ||
| shutil.rmtree(destination) | ||
| shutil.copytree(item, destination, dirs_exist_ok=True) | ||
| print(f"Updated existing skill at {destination}") | ||
| else: | ||
| warnings.warn( | ||
| f"Skill at {destination} already exists. " | ||
| "Use '--update' flag to overwrite." | ||
| ) | ||
| continue | ||
| # clone the skills repository and deploy requested skills | ||
| with cloned_skills() as tmp_path: | ||
| skills_brief_dict = json.loads((tmp_path / "skills.json").read_text()) | ||
| if args.requested_skill_names is not None: | ||
| unknown_names = [ | ||
| name | ||
| for name in args.requested_skill_names | ||
| if name not in skills_brief_dict | ||
| ] | ||
| if unknown_names: | ||
| raise ValueError( | ||
| f"Skill(s) {unknown_names} not found. " | ||
| "Run 'agentify list' to see available skills." | ||
| ) | ||
| for skill_name in skills_brief_dict: | ||
| if ( | ||
| args.requested_skill_names is not None | ||
| and skill_name not in args.requested_skill_names | ||
| ): | ||
| # skip when skill is not requested | ||
| continue | ||
| subprocess.run( | ||
| [ | ||
| "git", | ||
| "-C", | ||
| str(tmp_path), | ||
| "sparse-checkout", | ||
| "set", | ||
| "--no-cone", | ||
| f"{skill_name}/", | ||
| ], | ||
| check=True, | ||
| capture_output=True, | ||
| ) | ||
| destination = dest_dir / skill_name | ||
| if destination.exists(): | ||
| if args.update: | ||
| shutil.rmtree(destination) | ||
| shutil.copytree( | ||
| tmp_path / skill_name, destination, dirs_exist_ok=True | ||
| ) | ||
| print(f"Updated existing skill at {destination}") | ||
| else: | ||
| shutil.copytree(item, destination, dirs_exist_ok=True) | ||
| print( | ||
| f"Skill {item.name} has been deployed to {destination}" | ||
| warnings.warn( | ||
| f"Skill at {destination} already exists. " | ||
| "Use '--update' flag to overwrite." | ||
| ) | ||
| continue | ||
| else: | ||
| shutil.copytree( | ||
| tmp_path / skill_name, destination, dirs_exist_ok=True | ||
| ) | ||
| print(f"Skill {skill_name} has been deployed to {destination}") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back 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.
Use
sparse-checkoutto only download part of the repo