github-agent 1.4.1__py3-none-any.whl → 1.4.2__py3-none-any.whl
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.
- github_agent/agent_server.py +1 -1
- github_agent/api/api_client_repos.py +18 -2
- github_agent/mcp/mcp_repo.py +4 -1
- github_agent/mcp_server.py +4 -1
- github_agent/skills/github-tools/scripts/inspect_pr_checks.py +3 -3
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/METADATA +3 -3
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/RECORD +12 -12
- tests/test_org_crud.py +48 -0
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/WHEEL +0 -0
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/entry_points.txt +0 -0
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/licenses/LICENSE +0 -0
- {github_agent-1.4.1.dist-info → github_agent-1.4.2.dist-info}/top_level.txt +0 -0
github_agent/agent_server.py
CHANGED
|
@@ -52,11 +52,27 @@ class Api(BaseApiClient):
|
|
|
52
52
|
|
|
53
53
|
@require_auth
|
|
54
54
|
def create_repository(self, name: str, **kwargs) -> Response:
|
|
55
|
-
"""Create a
|
|
55
|
+
"""Create a repository for the authenticated user, or for an organization when 'org' is given.
|
|
56
|
+
|
|
57
|
+
Without ``org``: POST /user/repos — the repository is created under
|
|
58
|
+
the authenticated user's personal account.
|
|
59
|
+
|
|
60
|
+
With ``org``: POST /orgs/{org}/repos (same payload shape as
|
|
61
|
+
``create_organization_repository``). ``org`` is consumed as the URL
|
|
62
|
+
path segment and is never forwarded as a JSON body field. This
|
|
63
|
+
distinction matters: GitHub's /user/repos endpoint silently ignores
|
|
64
|
+
an unrecognized "org" body field instead of rejecting it, which
|
|
65
|
+
previously let a caller pass ``org=...`` expecting an organization
|
|
66
|
+
repository and get a 201 Created — with the repository silently
|
|
67
|
+
created under the personal account instead (a wrong-target bug, not
|
|
68
|
+
a clean failure).
|
|
69
|
+
"""
|
|
56
70
|
try:
|
|
71
|
+
org = kwargs.pop("org", None)
|
|
57
72
|
payload = {"name": name, **kwargs}
|
|
73
|
+
url = f"{self.url}/orgs/{org}/repos" if org else f"{self.url}/user/repos"
|
|
58
74
|
response = self._session.post(
|
|
59
|
-
url=
|
|
75
|
+
url=url,
|
|
60
76
|
json=payload,
|
|
61
77
|
headers=self.headers,
|
|
62
78
|
verify=self.verify,
|
github_agent/mcp/mcp_repo.py
CHANGED
|
@@ -90,7 +90,10 @@ def register_repo_tools(mcp: FastMCP):
|
|
|
90
90
|
- 'get': {"owner", "repo"} — a single repository.
|
|
91
91
|
- 'create': {"name", plus payload fields such as description,
|
|
92
92
|
private, auto_init, ...} — create a repository for the
|
|
93
|
-
authenticated user.
|
|
93
|
+
authenticated user. Pass "org" to create it inside an
|
|
94
|
+
organization instead (POST /orgs/{org}/repos rather than
|
|
95
|
+
POST /user/repos); "org" is consumed as the URL path segment
|
|
96
|
+
and is never sent in the request body.
|
|
94
97
|
- 'delete': {"owner", "repo"} — delete a repository.
|
|
95
98
|
- 'update': {"owner", "repo", plus mutable repository settings} —
|
|
96
99
|
PATCH /repos/{owner}/{repo}.
|
github_agent/mcp_server.py
CHANGED
|
@@ -191,7 +191,10 @@ def register_repo_tools(mcp: FastMCP):
|
|
|
191
191
|
- 'get': {"owner", "repo"} — a single repository.
|
|
192
192
|
- 'create': {"name", plus payload fields such as description,
|
|
193
193
|
private, auto_init, ...} — create a repository for the
|
|
194
|
-
authenticated user.
|
|
194
|
+
authenticated user. Pass "org" to create it inside an
|
|
195
|
+
organization instead (POST /orgs/{org}/repos rather than
|
|
196
|
+
POST /user/repos); "org" is consumed as the URL path segment
|
|
197
|
+
and is never sent in the request body.
|
|
195
198
|
- 'delete': {"owner", "repo"} — delete a repository.
|
|
196
199
|
- 'update': {"owner", "repo", plus mutable repository settings} —
|
|
197
200
|
PATCH /repos/{owner}/{repo}.
|
|
@@ -58,7 +58,7 @@ class GhResult:
|
|
|
58
58
|
|
|
59
59
|
def run_gh_command(args: Sequence[str], cwd: Path) -> GhResult:
|
|
60
60
|
process = subprocess.run(
|
|
61
|
-
["gh", *args],
|
|
61
|
+
[which("gh") or "gh", *args],
|
|
62
62
|
cwd=cwd,
|
|
63
63
|
text=True,
|
|
64
64
|
capture_output=True,
|
|
@@ -68,7 +68,7 @@ def run_gh_command(args: Sequence[str], cwd: Path) -> GhResult:
|
|
|
68
68
|
|
|
69
69
|
def run_gh_command_raw(args: Sequence[str], cwd: Path) -> tuple[int, bytes, str]:
|
|
70
70
|
process = subprocess.run(
|
|
71
|
-
["gh", *args],
|
|
71
|
+
[which("gh") or "gh", *args],
|
|
72
72
|
cwd=cwd,
|
|
73
73
|
capture_output=True,
|
|
74
74
|
)
|
|
@@ -144,7 +144,7 @@ def main() -> int:
|
|
|
144
144
|
|
|
145
145
|
def find_git_root(start: Path) -> Path | None:
|
|
146
146
|
result = subprocess.run(
|
|
147
|
-
["git", "rev-parse", "--show-toplevel"],
|
|
147
|
+
[which("git") or "git", "rev-parse", "--show-toplevel"],
|
|
148
148
|
cwd=start,
|
|
149
149
|
text=True,
|
|
150
150
|
capture_output=True,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-agent
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: GitHub Agent for MCP
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -48,7 +48,7 @@ Dynamic: license-file
|
|
|
48
48
|

|
|
49
49
|

|
|
50
50
|
|
|
51
|
-
*Version: 1.4.
|
|
51
|
+
*Version: 1.4.2*
|
|
52
52
|
|
|
53
53
|
> **Documentation** — Installation, deployment, and usage across the MCP, API, and
|
|
54
54
|
> CLI interfaces, including the integrated A2A agent server, are maintained in the
|
|
@@ -129,7 +129,7 @@ _Auto-generated from the live MCP server — do not edit by hand._
|
|
|
129
129
|
| `github_create_pull_request` | `APITOOL` | Create a new pull request in a repository. |
|
|
130
130
|
| `github_create_pull_request_review` | `APITOOL` | Create a review on a pull request. |
|
|
131
131
|
| `github_create_release` | `APITOOL` | Create a new repository release. |
|
|
132
|
-
| `github_create_repository` | `APITOOL` | Create a
|
|
132
|
+
| `github_create_repository` | `APITOOL` | Create a repository for the authenticated user, or for an organization when 'org' is given. |
|
|
133
133
|
| `github_delete_branch` | `APITOOL` | Delete a branch in a repository. |
|
|
134
134
|
| `github_delete_branch_protection` | `APITOOL` | Delete branch protection configuration. |
|
|
135
135
|
| `github_delete_content` | `APITOOL` | Delete a file in a repository. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
github_agent/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
2
2
|
github_agent/__main__.py,sha256=ZXoYRjLxhBFa4W12BvkIfSAxR-LkWhXzr-zfOYW1Tlc,98
|
|
3
|
-
github_agent/agent_server.py,sha256=
|
|
3
|
+
github_agent/agent_server.py,sha256=RFl7zFOvCSZi5b2UnAPA2njfsH-1dkY0TohWtCC3-jg,2444
|
|
4
4
|
github_agent/api_client.py,sha256=7di4nSXsOwMsrOchTkGYU2aKKv89WJfUxbpXwbeAkSc,1496
|
|
5
5
|
github_agent/auth.py,sha256=PqDJwoj8zIgXBQ2fJRHlpEpITnU7Bluopb1YPvAiPcI,5316
|
|
6
6
|
github_agent/github_gql.py,sha256=1LkixT67A6oYQhNS-9IofpL8kEldwe6evsekDfvOssA,4465
|
|
@@ -8,7 +8,7 @@ github_agent/github_input_models.py,sha256=yqqPGHb206th736MZvbnxq9F1JRsBUBODNeNV
|
|
|
8
8
|
github_agent/github_response_models.py,sha256=mllSt0frBgzklUtfuHywJ2Ald3m99So948Xikt3H2Tc,8859
|
|
9
9
|
github_agent/kg_ingest.py,sha256=GIFypvwm7KKSkwlzZKqYPUEEOVwQ7pm90Ll0FMgkFio,17964
|
|
10
10
|
github_agent/mcp_config.json,sha256=2OOXrwO1sDLyHQqpZwhvDHizPIe3by6YmK4KFE333gI,23
|
|
11
|
-
github_agent/mcp_server.py,sha256=
|
|
11
|
+
github_agent/mcp_server.py,sha256=wP9Glty2_wguptoRY8BiO4JmGv3a95Mm9WhCgTxT3sU,103656
|
|
12
12
|
github_agent/api/__init__.py,sha256=ntaEPqk-dsAV3HyyDLc2hYpc9nTTyG5CKI-SVDDjc24,27
|
|
13
13
|
github_agent/api/api_client_base.py,sha256=KxygEFTkkbAuQFWd3KHWkIyPLWAh3gMq7dSQmXvbn8c,7191
|
|
14
14
|
github_agent/api/api_client_branches.py,sha256=LjSB7pS1NG6hryU00QBN_VFw6SXPFkg1o1LaPwtUQnY,4374
|
|
@@ -20,7 +20,7 @@ github_agent/api/api_client_orgs.py,sha256=VzvIUJNO4k-uPrsfGKe_0H03WfvCwMjG7lxpo
|
|
|
20
20
|
github_agent/api/api_client_pages.py,sha256=bRf7Nd-FAVsQQURu9KiSqGvwM6jqhkyXXskZn5BsA8U,9263
|
|
21
21
|
github_agent/api/api_client_pulls.py,sha256=N8My4chqgqEd-ojh4YJljt27oAQyHqWYz34qUwqOyQc,6261
|
|
22
22
|
github_agent/api/api_client_releases.py,sha256=UCv2-Jla59VP_4Fe2hrM6dbIm1OmbOAhtQPIyl8zf4k,4031
|
|
23
|
-
github_agent/api/api_client_repos.py,sha256=
|
|
23
|
+
github_agent/api/api_client_repos.py,sha256=y3-4ndz0KliD8KGYRLekU96w82Wkf_-__FVld_WryUU,9152
|
|
24
24
|
github_agent/api/api_client_search.py,sha256=ZoOmWoU3XBJZliryv1MGeOqGwPI9eaM3NQxTl5xehNM,2262
|
|
25
25
|
github_agent/api/api_client_workflows.py,sha256=13UUVVXUZAFi7suVGThrVPf3p6nRSPGu2wecEzPhtNo,6357
|
|
26
26
|
github_agent/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -36,7 +36,7 @@ github_agent/mcp/mcp_issue.py,sha256=O-XuLhSECo4_2pwBKOHX3_wAAt1zYYVKm6gV3w5fEGk
|
|
|
36
36
|
github_agent/mcp/mcp_org.py,sha256=cqVluVF20Ixrz8g9RcEQOxuwwkibL0xBeZDNQxZ4qFI,12531
|
|
37
37
|
github_agent/mcp/mcp_pull.py,sha256=UcBExnwrPo5rntdb9KBc3Y-qfQHH3tTAre6XtP5t8Qc,11365
|
|
38
38
|
github_agent/mcp/mcp_release.py,sha256=gCRDbw1umP4AoRjTeFiolL0ug_5L4iOFslw8VE1vPTo,6139
|
|
39
|
-
github_agent/mcp/mcp_repo.py,sha256=
|
|
39
|
+
github_agent/mcp/mcp_repo.py,sha256=wjc-hwyB90DhYptkT4mvNYzibiLgM-LrwWInVwFIfnw,19236
|
|
40
40
|
github_agent/mcp/mcp_search.py,sha256=-lUxFEAgP-VGDsrPQQZzschHDaslYH8NkS43RJjnzaA,2828
|
|
41
41
|
github_agent/ontology/__init__.py,sha256=Rx6fxBQDfu9477JDTdjgnRVGr4r9IqLHzTlL2lErFoc,544
|
|
42
42
|
github_agent/ontology/github.ttl,sha256=rQrW0pUUOzhyWGa1tcWagk8Qv8Qhl5SsLZoidPEbvbU,9150
|
|
@@ -66,12 +66,12 @@ github_agent/skills/github-repository-management/SKILL.md,sha256=CW78YptyNbZ0JxY
|
|
|
66
66
|
github_agent/skills/github-tools/SKILL.md,sha256=fGJXdrxJQKJ75xn9veng9EbY4rTV5ivaM4mQsKu__pA,3761
|
|
67
67
|
github_agent/skills/github-tools/code-reviewer.md,sha256=f1Mo3KEssgAAWunUOG9jqbCstzXs5X-C2yBrSjGJzK4,3385
|
|
68
68
|
github_agent/skills/github-tools/scripts/fetch_comments.py,sha256=LkI94CFZZ5HhvNm5deurEAHBSzOe_7HKgiV9AOQYSGU,6683
|
|
69
|
-
github_agent/skills/github-tools/scripts/inspect_pr_checks.py,sha256=
|
|
69
|
+
github_agent/skills/github-tools/scripts/inspect_pr_checks.py,sha256=wf4mxwA1wpJdfApfqYKOY9BPNKyf1RJLOi0X2whGbzc,15524
|
|
70
70
|
github_agent/skills/github-triage-resolver/SKILL.md,sha256=6-_p-oYgRmYTSWih7kjcTp1_MgEzTZhaCigs0yyGZJ0,6448
|
|
71
71
|
github_agent/skills/github-triage-resolver/references/resolution-rules.md,sha256=7F7DCYvGQVQhc1a7Hfo7KRiaB4aLffHGwpatUDLVr5Q,3670
|
|
72
72
|
github_agent/skills/github-triage-resolver/scripts/classify_safe.py,sha256=pTnWKi8HgFRvPqthAeb8Vv0hvw4rrV2VqY7FiSHSTtk,7546
|
|
73
73
|
github_agent/skills/github-triage-resolver/scripts/gh_write.py,sha256=uxdCn7QGy_GM4g5z_sEABX2J5ha4jn1r7dkcq9Uh8ko,4846
|
|
74
|
-
github_agent-1.4.
|
|
74
|
+
github_agent-1.4.2.dist-info/licenses/LICENSE,sha256=5ALbh4fIALWVsUhO7q1nFT1bQb-CL9sWKf7p3GgLEG8,1070
|
|
75
75
|
scripts/security_sanitizer.py,sha256=_T9ImV5uya4yCdu2qfUb7KA67APWpR5-_Z_JaG_vk-w,6198
|
|
76
76
|
scripts/validate_a2a_agent.py,sha256=4VgvmU3qre8jSQdsrxaGQ6oMlbn92iw7A2WseGhzwrw,6503
|
|
77
77
|
scripts/verify_api_integration.py,sha256=iKEBzGtrhoLlxUNCr3F4NMJTw9iLJ_PFuUBhGE0F2xk,9926
|
|
@@ -89,11 +89,11 @@ tests/test_init_dynamics.py,sha256=54ekT599BuarmlEsU6MnXIdwpsWb_6eHgjl_EgMHYfU,1
|
|
|
89
89
|
tests/test_kg_ingest.py,sha256=XADorqbRtP6CJ0Z_gzvB3pHNX9glfjSvImSdZR7ZofM,9153
|
|
90
90
|
tests/test_mcp_coverage.py,sha256=QYAcJKRf6gyrq3yNEMN_pdCM1G0vMxzEisFTnkgxiM8,34807
|
|
91
91
|
tests/test_model_fields.py,sha256=GvVFFedjdL0KBl328-NZ0SM6olv7muiglsMh0Vd59As,3388
|
|
92
|
-
tests/test_org_crud.py,sha256=
|
|
92
|
+
tests/test_org_crud.py,sha256=4yTCPs1cXc8pr-RUMyGFY5fLE7zdTuE4AGFCw_R3Hso,20225
|
|
93
93
|
tests/test_pages.py,sha256=apxZjqO5ODlLTAAqJvsrwHo6fR9KJVkfOg8Flni9r7o,18982
|
|
94
94
|
tests/test_startup.py,sha256=JjJ9PxkmeOOCGIvj1wYN7KSq10IoQKF76CQNEK896Yw,1339
|
|
95
|
-
github_agent-1.4.
|
|
96
|
-
github_agent-1.4.
|
|
97
|
-
github_agent-1.4.
|
|
98
|
-
github_agent-1.4.
|
|
99
|
-
github_agent-1.4.
|
|
95
|
+
github_agent-1.4.2.dist-info/METADATA,sha256=Pd5n4SZxktzKXELiHOeFaZ_J5hfM7iOvfkRQtnM4R8M,33271
|
|
96
|
+
github_agent-1.4.2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
97
|
+
github_agent-1.4.2.dist-info/entry_points.txt,sha256=DO8QEo43x_KU9rhU6ALKdbP9iqh8WuOD6RGO01cFoHc,422
|
|
98
|
+
github_agent-1.4.2.dist-info/top_level.txt,sha256=tHoi3iPtvMB4uA-YJiZAtTxISOB0xVV2HZUfDMM3VQI,27
|
|
99
|
+
github_agent-1.4.2.dist-info/RECORD,,
|
tests/test_org_crud.py
CHANGED
|
@@ -263,6 +263,54 @@ def test_org_repo_create_payload_parity_with_user_repo_create(mock_session):
|
|
|
263
263
|
assert org_call.kwargs["url"] == "https://api.github.com/orgs/Knuckles-Team/repos"
|
|
264
264
|
|
|
265
265
|
|
|
266
|
+
def test_create_repository_without_org_posts_to_user_repos(mock_session):
|
|
267
|
+
"""Back-compat: no 'org' kwarg -> POST /user/repos, unchanged behavior."""
|
|
268
|
+
api = Api(token="test")
|
|
269
|
+
mock_session.post.return_value = make_response(
|
|
270
|
+
status_code=201, json_data=REPO_PAYLOAD
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
res = api.create_repository(name="service", private=True, description="d")
|
|
274
|
+
|
|
275
|
+
assert isinstance(res.data, Repository)
|
|
276
|
+
call = mock_session.post.call_args
|
|
277
|
+
assert call.kwargs["url"] == "https://api.github.com/user/repos"
|
|
278
|
+
assert call.kwargs["json"] == {
|
|
279
|
+
"name": "service",
|
|
280
|
+
"private": True,
|
|
281
|
+
"description": "d",
|
|
282
|
+
}
|
|
283
|
+
assert "org" not in call.kwargs["json"]
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def test_create_repository_with_org_kwarg_routes_to_org_repos(mock_session):
|
|
287
|
+
"""Regression test for the silent-wrong-target bug: passing 'org' to
|
|
288
|
+
create_repository must POST to /orgs/{org}/repos (not /user/repos),
|
|
289
|
+
and 'org' must never leak into the JSON body — GitHub's /user/repos
|
|
290
|
+
endpoint silently ignores an unrecognized "org" field rather than
|
|
291
|
+
erroring, which previously caused the repo to be created under the
|
|
292
|
+
personal account instead of the intended organization.
|
|
293
|
+
"""
|
|
294
|
+
api = Api(token="test")
|
|
295
|
+
mock_session.post.return_value = make_response(
|
|
296
|
+
status_code=201, json_data=REPO_PAYLOAD
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
res = api.create_repository(
|
|
300
|
+
name="service", org="Knuckles-Team", private=True, description="d"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
assert isinstance(res.data, Repository)
|
|
304
|
+
call = mock_session.post.call_args
|
|
305
|
+
assert call.kwargs["url"] == "https://api.github.com/orgs/Knuckles-Team/repos"
|
|
306
|
+
assert call.kwargs["json"] == {
|
|
307
|
+
"name": "service",
|
|
308
|
+
"private": True,
|
|
309
|
+
"description": "d",
|
|
310
|
+
}
|
|
311
|
+
assert "org" not in call.kwargs["json"]
|
|
312
|
+
|
|
313
|
+
|
|
266
314
|
def test_get_organization_membership(mock_session):
|
|
267
315
|
api = Api(token="test")
|
|
268
316
|
mock_session.get.return_value = make_response(json_data=MEMBERSHIP_PAYLOAD)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|