gh-agent-sync 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gh_agent_sync-0.1.0/PKG-INFO +143 -0
- gh_agent_sync-0.1.0/README.md +123 -0
- gh_agent_sync-0.1.0/pyproject.toml +37 -0
- gh_agent_sync-0.1.0/setup.cfg +4 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync/__init__.py +0 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync/__main__.py +6 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync/cli.py +158 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync/git_mcp.py +131 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync.egg-info/PKG-INFO +143 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync.egg-info/SOURCES.txt +11 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync.egg-info/dependency_links.txt +1 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync.egg-info/entry_points.txt +2 -0
- gh_agent_sync-0.1.0/src/gh_agent_sync.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gh-agent-sync
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Link agents and skills from awesome-copilot to your local repository. Supports MCP-based git operations.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/msandeep12/gh-agent-sync
|
|
7
|
+
Project-URL: Repository, https://github.com/msandeep12/gh-agent-sync
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Copilot Linker
|
|
22
|
+
|
|
23
|
+
A cross-platform Python utility to link agents and skills from the [awesome-copilot](https://github.com/github/awesome-copilot) repository to any local git repository.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Install from source:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or for development:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install -e .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
From PyPI (once published):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install gh-agent-sync
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
Run the utility from the root of your git repository:
|
|
48
|
+
|
|
49
|
+
### Link Agents and Skills
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
gh-agent-sync link
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or specify a custom repository:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
gh-agent-sync link --url https://github.com/your-org/your-agents-repo
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This will:
|
|
62
|
+
- Clone or update the awesome-copilot repository into `.github/awesome-copilot`
|
|
63
|
+
- Create symbolic links (or copies if symlinks fail) to `.github/agents` and `.github/skills`
|
|
64
|
+
- Add the linked paths to `.gitignore` to prevent them from being committed
|
|
65
|
+
|
|
66
|
+
### Undo Linking
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
gh-agent-sync undo
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This will:
|
|
73
|
+
- Remove the `.github/agents` and `.github/skills` directories
|
|
74
|
+
- Remove the cloned `.github/awesome-copilot` repository
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
### Building
|
|
79
|
+
|
|
80
|
+
To build the package:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python -m build
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Publishing
|
|
87
|
+
|
|
88
|
+
1. Create a release on GitHub
|
|
89
|
+
2. The CI/CD workflow will automatically build and publish to PyPI
|
|
90
|
+
|
|
91
|
+
Make sure to set up PyPI API tokens in the repository secrets if needed.
|
|
92
|
+
|
|
93
|
+
## What it does
|
|
94
|
+
|
|
95
|
+
- Checks if the current directory is a git repository
|
|
96
|
+
- Clones or updates the awesome-copilot repository into `.github/awesome-copilot`
|
|
97
|
+
- Creates symbolic links (or copies if symlinks fail):
|
|
98
|
+
- `.github/agents` → `.github/awesome-copilot/agents`
|
|
99
|
+
- `.github/skills` → `.github/awesome-copilot/skills`
|
|
100
|
+
- Adds linked paths to `.gitignore`
|
|
101
|
+
|
|
102
|
+
This allows you to use the agents and skills from awesome-copilot in your repository without copying the files directly.
|
|
103
|
+
|
|
104
|
+
## Requirements
|
|
105
|
+
|
|
106
|
+
- Python 3.8+
|
|
107
|
+
- Git
|
|
108
|
+
- Internet connection for cloning the repository
|
|
109
|
+
|
|
110
|
+
## Notes
|
|
111
|
+
|
|
112
|
+
- On systems where symlinks are not supported or require special permissions, the utility will fall back to copying the directories.
|
|
113
|
+
- The utility creates links/copies, so changes in the awesome-copilot repo will be reflected in your links (after updating with `git pull` in the cloned directory).
|
|
114
|
+
|
|
115
|
+
## Architecture
|
|
116
|
+
|
|
117
|
+
### MCP Integration
|
|
118
|
+
|
|
119
|
+
This tool uses a **Model Context Protocol (MCP)** based git server for all git operations. This provides:
|
|
120
|
+
|
|
121
|
+
- Type-safe git operations
|
|
122
|
+
- Better error handling
|
|
123
|
+
- Easier testing and mocking
|
|
124
|
+
- Potential for distributed git operations
|
|
125
|
+
- Integration with AI agents via MCP
|
|
126
|
+
|
|
127
|
+
The `GitMCPServer` class in `src/gh_agent_sync/git_mcp.py` provides standardized interfaces for:
|
|
128
|
+
- `is_git_repo()` - Check if in a git repository
|
|
129
|
+
- `clone()` - Clone a repository
|
|
130
|
+
- `pull()` - Pull updates
|
|
131
|
+
- `add()` - Stage files
|
|
132
|
+
- `commit()` - Commit changes
|
|
133
|
+
- `push()` - Push to remote
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
We use a pull request workflow with automated versioning and release management. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:
|
|
138
|
+
|
|
139
|
+
- How to create pull requests
|
|
140
|
+
- Conventional commit message style
|
|
141
|
+
- Automated versioning and release process
|
|
142
|
+
|
|
143
|
+
All commits should follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Copilot Linker
|
|
2
|
+
|
|
3
|
+
A cross-platform Python utility to link agents and skills from the [awesome-copilot](https://github.com/github/awesome-copilot) repository to any local git repository.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install from source:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or for development:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install -e .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
From PyPI (once published):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install gh-agent-sync
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Run the utility from the root of your git repository:
|
|
28
|
+
|
|
29
|
+
### Link Agents and Skills
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gh-agent-sync link
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or specify a custom repository:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
gh-agent-sync link --url https://github.com/your-org/your-agents-repo
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This will:
|
|
42
|
+
- Clone or update the awesome-copilot repository into `.github/awesome-copilot`
|
|
43
|
+
- Create symbolic links (or copies if symlinks fail) to `.github/agents` and `.github/skills`
|
|
44
|
+
- Add the linked paths to `.gitignore` to prevent them from being committed
|
|
45
|
+
|
|
46
|
+
### Undo Linking
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
gh-agent-sync undo
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This will:
|
|
53
|
+
- Remove the `.github/agents` and `.github/skills` directories
|
|
54
|
+
- Remove the cloned `.github/awesome-copilot` repository
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
### Building
|
|
59
|
+
|
|
60
|
+
To build the package:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python -m build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Publishing
|
|
67
|
+
|
|
68
|
+
1. Create a release on GitHub
|
|
69
|
+
2. The CI/CD workflow will automatically build and publish to PyPI
|
|
70
|
+
|
|
71
|
+
Make sure to set up PyPI API tokens in the repository secrets if needed.
|
|
72
|
+
|
|
73
|
+
## What it does
|
|
74
|
+
|
|
75
|
+
- Checks if the current directory is a git repository
|
|
76
|
+
- Clones or updates the awesome-copilot repository into `.github/awesome-copilot`
|
|
77
|
+
- Creates symbolic links (or copies if symlinks fail):
|
|
78
|
+
- `.github/agents` → `.github/awesome-copilot/agents`
|
|
79
|
+
- `.github/skills` → `.github/awesome-copilot/skills`
|
|
80
|
+
- Adds linked paths to `.gitignore`
|
|
81
|
+
|
|
82
|
+
This allows you to use the agents and skills from awesome-copilot in your repository without copying the files directly.
|
|
83
|
+
|
|
84
|
+
## Requirements
|
|
85
|
+
|
|
86
|
+
- Python 3.8+
|
|
87
|
+
- Git
|
|
88
|
+
- Internet connection for cloning the repository
|
|
89
|
+
|
|
90
|
+
## Notes
|
|
91
|
+
|
|
92
|
+
- On systems where symlinks are not supported or require special permissions, the utility will fall back to copying the directories.
|
|
93
|
+
- The utility creates links/copies, so changes in the awesome-copilot repo will be reflected in your links (after updating with `git pull` in the cloned directory).
|
|
94
|
+
|
|
95
|
+
## Architecture
|
|
96
|
+
|
|
97
|
+
### MCP Integration
|
|
98
|
+
|
|
99
|
+
This tool uses a **Model Context Protocol (MCP)** based git server for all git operations. This provides:
|
|
100
|
+
|
|
101
|
+
- Type-safe git operations
|
|
102
|
+
- Better error handling
|
|
103
|
+
- Easier testing and mocking
|
|
104
|
+
- Potential for distributed git operations
|
|
105
|
+
- Integration with AI agents via MCP
|
|
106
|
+
|
|
107
|
+
The `GitMCPServer` class in `src/gh_agent_sync/git_mcp.py` provides standardized interfaces for:
|
|
108
|
+
- `is_git_repo()` - Check if in a git repository
|
|
109
|
+
- `clone()` - Clone a repository
|
|
110
|
+
- `pull()` - Pull updates
|
|
111
|
+
- `add()` - Stage files
|
|
112
|
+
- `commit()` - Commit changes
|
|
113
|
+
- `push()` - Push to remote
|
|
114
|
+
|
|
115
|
+
## Contributing
|
|
116
|
+
|
|
117
|
+
We use a pull request workflow with automated versioning and release management. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:
|
|
118
|
+
|
|
119
|
+
- How to create pull requests
|
|
120
|
+
- Conventional commit message style
|
|
121
|
+
- Automated versioning and release process
|
|
122
|
+
|
|
123
|
+
All commits should follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gh-agent-sync"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Link agents and skills from awesome-copilot to your local repository. Supports MCP-based git operations."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
]
|
|
24
|
+
dependencies = []
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/msandeep12/gh-agent-sync"
|
|
28
|
+
Repository = "https://github.com/msandeep12/gh-agent-sync"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
gh-agent-sync = "gh_agent_sync.cli:main"
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["src"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-dir]
|
|
37
|
+
"" = "src"
|
|
File without changes
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Copilot Linker - Link agents and skills from awesome-copilot to local .github/
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import shutil
|
|
9
|
+
import argparse
|
|
10
|
+
import tempfile
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from .git_mcp import GitMCPServer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_git_repo():
|
|
16
|
+
"""Check if current directory is a git repository."""
|
|
17
|
+
return GitMCPServer.is_git_repo()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def clone_or_update_awesome_copilot(repo_url):
|
|
21
|
+
"""Clone the repository to a temporary directory and return the path.
|
|
22
|
+
|
|
23
|
+
This uses a temporary directory to keep the project directory clean.
|
|
24
|
+
The full repository is not stored in the project.
|
|
25
|
+
"""
|
|
26
|
+
temp_dir = tempfile.mkdtemp(prefix="gh-agent-sync-")
|
|
27
|
+
temp_path = Path(temp_dir)
|
|
28
|
+
|
|
29
|
+
print(f"Cloning repository to temporary directory...")
|
|
30
|
+
success, message = GitMCPServer.clone(repo_url, str(temp_path))
|
|
31
|
+
if not success:
|
|
32
|
+
print(f"Error: {message}")
|
|
33
|
+
shutil.rmtree(temp_path, ignore_errors=True)
|
|
34
|
+
return None
|
|
35
|
+
else:
|
|
36
|
+
print(message)
|
|
37
|
+
|
|
38
|
+
return temp_path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def create_link_or_copy(source, target):
|
|
42
|
+
"""Create a symlink or copy if symlink fails."""
|
|
43
|
+
source = Path(source)
|
|
44
|
+
target = Path(target)
|
|
45
|
+
|
|
46
|
+
if target.exists():
|
|
47
|
+
print(f"{target} already exists")
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# Try to create symlink
|
|
52
|
+
os.symlink(source, target, target_is_directory=True)
|
|
53
|
+
print(f"Created symlink: {target} -> {source}")
|
|
54
|
+
return True
|
|
55
|
+
except OSError as e:
|
|
56
|
+
print(f"Symlink failed ({e}), copying instead...")
|
|
57
|
+
try:
|
|
58
|
+
shutil.copytree(source, target)
|
|
59
|
+
print(f"Copied: {source} -> {target}")
|
|
60
|
+
return True
|
|
61
|
+
except Exception as e:
|
|
62
|
+
print(f"Copy failed: {e}")
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def remove_link(target):
|
|
67
|
+
"""Remove a link or copy."""
|
|
68
|
+
target = Path(target)
|
|
69
|
+
if target.exists():
|
|
70
|
+
if target.is_dir():
|
|
71
|
+
shutil.rmtree(target)
|
|
72
|
+
else:
|
|
73
|
+
target.unlink()
|
|
74
|
+
print(f"Removed {target}")
|
|
75
|
+
else:
|
|
76
|
+
print(f"{target} does not exist")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def add_to_gitignore():
|
|
80
|
+
"""Add linked paths to .gitignore."""
|
|
81
|
+
gitignore = Path(".gitignore")
|
|
82
|
+
entries = [".github/agents", ".github/skills"]
|
|
83
|
+
|
|
84
|
+
if gitignore.exists():
|
|
85
|
+
with open(gitignore, "r") as f:
|
|
86
|
+
content = f.read()
|
|
87
|
+
else:
|
|
88
|
+
content = ""
|
|
89
|
+
|
|
90
|
+
added = False
|
|
91
|
+
for entry in entries:
|
|
92
|
+
if entry not in content:
|
|
93
|
+
content += f"\n{entry}"
|
|
94
|
+
added = True
|
|
95
|
+
|
|
96
|
+
if added:
|
|
97
|
+
with open(gitignore, "w") as f:
|
|
98
|
+
f.write(content)
|
|
99
|
+
print("Added entries to .gitignore")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def link(repo_url):
|
|
103
|
+
"""Link agents and skills."""
|
|
104
|
+
# Ensure .github directory exists
|
|
105
|
+
Path(".github").mkdir(exist_ok=True)
|
|
106
|
+
|
|
107
|
+
# Clone repository to temporary directory
|
|
108
|
+
temp_repo = clone_or_update_awesome_copilot(repo_url)
|
|
109
|
+
if not temp_repo:
|
|
110
|
+
print("Failed to clone repository")
|
|
111
|
+
sys.exit(1)
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
# Create links from temporary directory
|
|
115
|
+
success = True
|
|
116
|
+
success &= create_link_or_copy(temp_repo / "agents", Path(".github/agents"))
|
|
117
|
+
success &= create_link_or_copy(temp_repo / "skills", Path(".github/skills"))
|
|
118
|
+
|
|
119
|
+
if success:
|
|
120
|
+
add_to_gitignore()
|
|
121
|
+
print("Done! Agents and skills are now linked to your repository.")
|
|
122
|
+
else:
|
|
123
|
+
print("Some links failed to create.")
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
finally:
|
|
126
|
+
# Clean up temporary directory
|
|
127
|
+
shutil.rmtree(temp_repo, ignore_errors=True)
|
|
128
|
+
print(f"Cleaned up temporary directory")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def undo():
|
|
132
|
+
"""Undo the linking."""
|
|
133
|
+
remove_link(".github/agents")
|
|
134
|
+
remove_link(".github/skills")
|
|
135
|
+
|
|
136
|
+
print("Undo complete. The agents and skills links have been removed.")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main():
|
|
140
|
+
"""Main function."""
|
|
141
|
+
parser = argparse.ArgumentParser(description="Link or undo linking of agents and skills from a repository")
|
|
142
|
+
parser.add_argument("command", choices=["link", "undo"], help="Command to run: link or undo")
|
|
143
|
+
parser.add_argument("--url", default="https://github.com/github/awesome-copilot", help="URL of the repository containing agents and skills (default: awesome-copilot)")
|
|
144
|
+
|
|
145
|
+
args = parser.parse_args()
|
|
146
|
+
|
|
147
|
+
if not is_git_repo():
|
|
148
|
+
print("Error: Not in a git repository")
|
|
149
|
+
sys.exit(1)
|
|
150
|
+
|
|
151
|
+
if args.command == "link":
|
|
152
|
+
link(args.url)
|
|
153
|
+
elif args.command == "undo":
|
|
154
|
+
undo()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
main()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Git MCP - Git operations via Model Context Protocol
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GitMCPServer:
|
|
12
|
+
"""Simple Git MCP Server for git operations."""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def is_git_repo() -> bool:
|
|
16
|
+
"""Check if current directory is a git repository."""
|
|
17
|
+
try:
|
|
18
|
+
subprocess.run(
|
|
19
|
+
["git", "rev-parse", "--git-dir"],
|
|
20
|
+
check=True,
|
|
21
|
+
capture_output=True,
|
|
22
|
+
text=True
|
|
23
|
+
)
|
|
24
|
+
return True
|
|
25
|
+
except subprocess.CalledProcessError:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def clone(repo_url: str, target_dir: str) -> Tuple[bool, str]:
|
|
30
|
+
"""Clone a git repository.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
repo_url: URL of the repository to clone
|
|
34
|
+
target_dir: Target directory for cloning
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Tuple of (success, message)
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
subprocess.run(
|
|
41
|
+
["git", "clone", repo_url, target_dir],
|
|
42
|
+
check=True,
|
|
43
|
+
capture_output=True,
|
|
44
|
+
text=True
|
|
45
|
+
)
|
|
46
|
+
return True, f"Cloned {repo_url} to {target_dir}"
|
|
47
|
+
except subprocess.CalledProcessError as e:
|
|
48
|
+
return False, f"Clone failed: {e.stderr}"
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def pull(repo_dir: str) -> Tuple[bool, str]:
|
|
52
|
+
"""Pull updates from a git repository.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
repo_dir: Directory of the repository
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Tuple of (success, message)
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
["git", "-C", repo_dir, "pull"],
|
|
63
|
+
check=True,
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True
|
|
66
|
+
)
|
|
67
|
+
return True, f"Updated repository: {result.stdout}"
|
|
68
|
+
except subprocess.CalledProcessError as e:
|
|
69
|
+
return False, f"Pull failed: {e.stderr}"
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def add(files: list, repo_dir: str = ".") -> Tuple[bool, str]:
|
|
73
|
+
"""Stage files in git.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
files: List of files to stage
|
|
77
|
+
repo_dir: Directory of the repository
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Tuple of (success, message)
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
cmd = ["git", "-C", repo_dir, "add"] + files
|
|
84
|
+
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
|
85
|
+
return True, f"Staged {len(files)} file(s)"
|
|
86
|
+
except subprocess.CalledProcessError as e:
|
|
87
|
+
return False, f"Add failed: {e.stderr}"
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def commit(message: str, repo_dir: str = ".") -> Tuple[bool, str]:
|
|
91
|
+
"""Commit changes to git.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
message: Commit message
|
|
95
|
+
repo_dir: Directory of the repository
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Tuple of (success, message)
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
result = subprocess.run(
|
|
102
|
+
["git", "-C", repo_dir, "commit", "-m", message],
|
|
103
|
+
check=True,
|
|
104
|
+
capture_output=True,
|
|
105
|
+
text=True
|
|
106
|
+
)
|
|
107
|
+
return True, f"Committed: {result.stdout}"
|
|
108
|
+
except subprocess.CalledProcessError as e:
|
|
109
|
+
return False, f"Commit failed: {e.stderr}"
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def push(branch: str = "main", repo_dir: str = ".") -> Tuple[bool, str]:
|
|
113
|
+
"""Push changes to remote repository.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
branch: Branch to push
|
|
117
|
+
repo_dir: Directory of the repository
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Tuple of (success, message)
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
result = subprocess.run(
|
|
124
|
+
["git", "-C", repo_dir, "push", "origin", branch],
|
|
125
|
+
check=True,
|
|
126
|
+
capture_output=True,
|
|
127
|
+
text=True
|
|
128
|
+
)
|
|
129
|
+
return True, f"Pushed: {result.stdout}"
|
|
130
|
+
except subprocess.CalledProcessError as e:
|
|
131
|
+
return False, f"Push failed: {e.stderr}"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gh-agent-sync
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Link agents and skills from awesome-copilot to your local repository. Supports MCP-based git operations.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/msandeep12/gh-agent-sync
|
|
7
|
+
Project-URL: Repository, https://github.com/msandeep12/gh-agent-sync
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Copilot Linker
|
|
22
|
+
|
|
23
|
+
A cross-platform Python utility to link agents and skills from the [awesome-copilot](https://github.com/github/awesome-copilot) repository to any local git repository.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Install from source:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or for development:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install -e .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
From PyPI (once published):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install gh-agent-sync
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
Run the utility from the root of your git repository:
|
|
48
|
+
|
|
49
|
+
### Link Agents and Skills
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
gh-agent-sync link
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or specify a custom repository:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
gh-agent-sync link --url https://github.com/your-org/your-agents-repo
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This will:
|
|
62
|
+
- Clone or update the awesome-copilot repository into `.github/awesome-copilot`
|
|
63
|
+
- Create symbolic links (or copies if symlinks fail) to `.github/agents` and `.github/skills`
|
|
64
|
+
- Add the linked paths to `.gitignore` to prevent them from being committed
|
|
65
|
+
|
|
66
|
+
### Undo Linking
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
gh-agent-sync undo
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This will:
|
|
73
|
+
- Remove the `.github/agents` and `.github/skills` directories
|
|
74
|
+
- Remove the cloned `.github/awesome-copilot` repository
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
### Building
|
|
79
|
+
|
|
80
|
+
To build the package:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python -m build
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Publishing
|
|
87
|
+
|
|
88
|
+
1. Create a release on GitHub
|
|
89
|
+
2. The CI/CD workflow will automatically build and publish to PyPI
|
|
90
|
+
|
|
91
|
+
Make sure to set up PyPI API tokens in the repository secrets if needed.
|
|
92
|
+
|
|
93
|
+
## What it does
|
|
94
|
+
|
|
95
|
+
- Checks if the current directory is a git repository
|
|
96
|
+
- Clones or updates the awesome-copilot repository into `.github/awesome-copilot`
|
|
97
|
+
- Creates symbolic links (or copies if symlinks fail):
|
|
98
|
+
- `.github/agents` → `.github/awesome-copilot/agents`
|
|
99
|
+
- `.github/skills` → `.github/awesome-copilot/skills`
|
|
100
|
+
- Adds linked paths to `.gitignore`
|
|
101
|
+
|
|
102
|
+
This allows you to use the agents and skills from awesome-copilot in your repository without copying the files directly.
|
|
103
|
+
|
|
104
|
+
## Requirements
|
|
105
|
+
|
|
106
|
+
- Python 3.8+
|
|
107
|
+
- Git
|
|
108
|
+
- Internet connection for cloning the repository
|
|
109
|
+
|
|
110
|
+
## Notes
|
|
111
|
+
|
|
112
|
+
- On systems where symlinks are not supported or require special permissions, the utility will fall back to copying the directories.
|
|
113
|
+
- The utility creates links/copies, so changes in the awesome-copilot repo will be reflected in your links (after updating with `git pull` in the cloned directory).
|
|
114
|
+
|
|
115
|
+
## Architecture
|
|
116
|
+
|
|
117
|
+
### MCP Integration
|
|
118
|
+
|
|
119
|
+
This tool uses a **Model Context Protocol (MCP)** based git server for all git operations. This provides:
|
|
120
|
+
|
|
121
|
+
- Type-safe git operations
|
|
122
|
+
- Better error handling
|
|
123
|
+
- Easier testing and mocking
|
|
124
|
+
- Potential for distributed git operations
|
|
125
|
+
- Integration with AI agents via MCP
|
|
126
|
+
|
|
127
|
+
The `GitMCPServer` class in `src/gh_agent_sync/git_mcp.py` provides standardized interfaces for:
|
|
128
|
+
- `is_git_repo()` - Check if in a git repository
|
|
129
|
+
- `clone()` - Clone a repository
|
|
130
|
+
- `pull()` - Pull updates
|
|
131
|
+
- `add()` - Stage files
|
|
132
|
+
- `commit()` - Commit changes
|
|
133
|
+
- `push()` - Push to remote
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
We use a pull request workflow with automated versioning and release management. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines on:
|
|
138
|
+
|
|
139
|
+
- How to create pull requests
|
|
140
|
+
- Conventional commit message style
|
|
141
|
+
- Automated versioning and release process
|
|
142
|
+
|
|
143
|
+
All commits should follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/gh_agent_sync/__init__.py
|
|
4
|
+
src/gh_agent_sync/__main__.py
|
|
5
|
+
src/gh_agent_sync/cli.py
|
|
6
|
+
src/gh_agent_sync/git_mcp.py
|
|
7
|
+
src/gh_agent_sync.egg-info/PKG-INFO
|
|
8
|
+
src/gh_agent_sync.egg-info/SOURCES.txt
|
|
9
|
+
src/gh_agent_sync.egg-info/dependency_links.txt
|
|
10
|
+
src/gh_agent_sync.egg-info/entry_points.txt
|
|
11
|
+
src/gh_agent_sync.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gh_agent_sync
|