agentic-devtools 0.2.548__py3-none-any.whl → 0.2.549__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.
- agentic_devtools/_version.py +2 -2
- agentic_devtools/cli/ci/github_provider.py +6 -0
- agentic_devtools/cli/ci/pipeline/runner.py +103 -12
- agentic_devtools/cli/ci/provider.py +4 -0
- {agentic_devtools-0.2.548.dist-info → agentic_devtools-0.2.549.dist-info}/METADATA +1 -1
- {agentic_devtools-0.2.548.dist-info → agentic_devtools-0.2.549.dist-info}/RECORD +9 -9
- {agentic_devtools-0.2.548.dist-info → agentic_devtools-0.2.549.dist-info}/WHEEL +0 -0
- {agentic_devtools-0.2.548.dist-info → agentic_devtools-0.2.549.dist-info}/entry_points.txt +0 -0
- {agentic_devtools-0.2.548.dist-info → agentic_devtools-0.2.549.dist-info}/licenses/LICENSE +0 -0
agentic_devtools/_version.py
CHANGED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.549'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 549)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -3924,6 +3924,12 @@ class GitHubActionsProvider(CIPlatformProvider):
|
|
|
3924
3924
|
files = _parse_paginated_json(response)
|
|
3925
3925
|
return [f["filename"] for f in files]
|
|
3926
3926
|
|
|
3927
|
+
@retry_with_backoff()
|
|
3928
|
+
def list_pr_commits(self, pr_number: int) -> list[dict[str, Any]]:
|
|
3929
|
+
"""Return paginated PR commits oldest first, with their parent SHAs."""
|
|
3930
|
+
response = _gh_api(self._repo_api(f"/pulls/{pr_number}/commits"), paginate=True)
|
|
3931
|
+
return _parse_paginated_json(response)
|
|
3932
|
+
|
|
3927
3933
|
@retry_with_backoff()
|
|
3928
3934
|
def get_check_annotations(self, check_run_id: int, limit: int) -> list[str]:
|
|
3929
3935
|
"""Get annotations from a check run."""
|
|
@@ -11,6 +11,7 @@ import re
|
|
|
11
11
|
import sys
|
|
12
12
|
import zlib
|
|
13
13
|
from collections.abc import Mapping, Sequence
|
|
14
|
+
from dataclasses import replace
|
|
14
15
|
from datetime import UTC, datetime
|
|
15
16
|
from typing import TypedDict, cast
|
|
16
17
|
|
|
@@ -578,6 +579,46 @@ def _find_recent_conflict_repair_head(
|
|
|
578
579
|
return marker_head
|
|
579
580
|
|
|
580
581
|
|
|
582
|
+
def _find_conflict_repair_output(
|
|
583
|
+
provider: CIPlatformProvider,
|
|
584
|
+
pr_number: int,
|
|
585
|
+
pre_head_sha: str,
|
|
586
|
+
current_head_sha: str,
|
|
587
|
+
) -> str:
|
|
588
|
+
"""Resolve the earliest repair child, falling back to the next PR commit."""
|
|
589
|
+
try:
|
|
590
|
+
commits = provider.list_pr_commits(pr_number)
|
|
591
|
+
if not isinstance(commits, list):
|
|
592
|
+
raise ValueError("PR commit list unavailable")
|
|
593
|
+
shas: list[str] = []
|
|
594
|
+
parent_shas: list[list[str]] = []
|
|
595
|
+
for commit in commits:
|
|
596
|
+
if not isinstance(commit, dict) or not isinstance(commit.get("sha"), str) or not commit["sha"]:
|
|
597
|
+
raise ValueError("PR commit SHA unavailable")
|
|
598
|
+
parents = commit.get("parents", [])
|
|
599
|
+
if not isinstance(parents, list) or any(
|
|
600
|
+
not isinstance(parent, dict) or not isinstance(parent.get("sha"), str) for parent in parents
|
|
601
|
+
):
|
|
602
|
+
raise ValueError("PR commit parents unavailable")
|
|
603
|
+
shas.append(commit["sha"])
|
|
604
|
+
parent_shas.append([parent["sha"] for parent in parents])
|
|
605
|
+
if pre_head_sha not in shas:
|
|
606
|
+
raise ValueError("pre-repair HEAD not found in PR commit list")
|
|
607
|
+
if current_head_sha not in shas or shas.index(current_head_sha) <= shas.index(pre_head_sha):
|
|
608
|
+
raise ValueError("current HEAD not found after pre-repair HEAD in PR commit list")
|
|
609
|
+
start = shas.index(pre_head_sha) + 1
|
|
610
|
+
end = shas.index(current_head_sha) + 1
|
|
611
|
+
for index in range(start, end):
|
|
612
|
+
if pre_head_sha in parent_shas[index]:
|
|
613
|
+
return shas[index]
|
|
614
|
+
return shas[start]
|
|
615
|
+
except Exception as exc:
|
|
616
|
+
if isinstance(exc, ProviderRateLimitError) and exc.is_rate_limit:
|
|
617
|
+
raise
|
|
618
|
+
logger.error("PR #%d: conflict-repair output unavailable: %s", pr_number, str(exc)[:200])
|
|
619
|
+
return ""
|
|
620
|
+
|
|
621
|
+
|
|
581
622
|
def _persist_conflict_repair_validation(
|
|
582
623
|
provider: CIPlatformProvider,
|
|
583
624
|
pr_number: int,
|
|
@@ -943,6 +984,56 @@ def run_pipeline(
|
|
|
943
984
|
f"PR #{current_snapshot.pr_number}: conflict-repair diff validation unavailable ({exc})"
|
|
944
985
|
)
|
|
945
986
|
logger.error(guard_block_reason)
|
|
987
|
+
repair_snapshot = current_snapshot
|
|
988
|
+
if pre_repair_head_sha:
|
|
989
|
+
repair_output_sha = _find_conflict_repair_output(
|
|
990
|
+
provider, current_snapshot.pr_number, pre_repair_head_sha, current_snapshot.head_sha
|
|
991
|
+
)
|
|
992
|
+
try:
|
|
993
|
+
if not repair_output_sha:
|
|
994
|
+
raise ValueError("conflict-repair output unavailable from PR commit list")
|
|
995
|
+
if repair_output_sha != current_snapshot.head_sha:
|
|
996
|
+
repair_files = provider.compute_diff_files(
|
|
997
|
+
base_branch=current_snapshot.base_branch,
|
|
998
|
+
sha=repair_output_sha,
|
|
999
|
+
base_sha=current_snapshot.base_sha,
|
|
1000
|
+
)
|
|
1001
|
+
if not isinstance(repair_files, list) or any(
|
|
1002
|
+
not isinstance(path, str) or not path for path in repair_files
|
|
1003
|
+
):
|
|
1004
|
+
raise ValueError("conflict-repair output file inventory unavailable")
|
|
1005
|
+
repair_hash = None
|
|
1006
|
+
try:
|
|
1007
|
+
repair_hash = provider.compute_diff_hash(
|
|
1008
|
+
base_branch=current_snapshot.base_branch,
|
|
1009
|
+
sha=repair_output_sha,
|
|
1010
|
+
base_sha=current_snapshot.base_sha,
|
|
1011
|
+
)
|
|
1012
|
+
except Exception as exc:
|
|
1013
|
+
if isinstance(exc, ProviderRateLimitError) and exc.is_rate_limit:
|
|
1014
|
+
raise
|
|
1015
|
+
logger.warning(
|
|
1016
|
+
"PR #%d: Failed to compute repair-output fingerprint for %s: %s",
|
|
1017
|
+
current_snapshot.pr_number,
|
|
1018
|
+
repair_output_sha[:8],
|
|
1019
|
+
str(exc)[:200],
|
|
1020
|
+
)
|
|
1021
|
+
repair_snapshot = replace(
|
|
1022
|
+
current_snapshot,
|
|
1023
|
+
head_sha=repair_output_sha,
|
|
1024
|
+
files=repair_files,
|
|
1025
|
+
diff_hash=repair_hash if isinstance(repair_hash, str) else "",
|
|
1026
|
+
diff_hash_available=isinstance(repair_hash, str) and bool(repair_hash),
|
|
1027
|
+
)
|
|
1028
|
+
except Exception as exc:
|
|
1029
|
+
if isinstance(exc, ProviderRateLimitError) and exc.is_rate_limit:
|
|
1030
|
+
raise
|
|
1031
|
+
guard_blocked = True
|
|
1032
|
+
guard_block_reason = (
|
|
1033
|
+
f"PR #{current_snapshot.pr_number}: conflict-repair diff validation unavailable ({exc})"
|
|
1034
|
+
)
|
|
1035
|
+
logger.error(guard_block_reason)
|
|
1036
|
+
pre_repair_head_sha = ""
|
|
946
1037
|
if pre_repair_head_sha:
|
|
947
1038
|
pre_repair_hash = ""
|
|
948
1039
|
pre_repair_hash_available = False
|
|
@@ -996,12 +1087,12 @@ def run_pipeline(
|
|
|
996
1087
|
cross_run_fingerprints_available = (
|
|
997
1088
|
bool(current_snapshot.base_sha)
|
|
998
1089
|
and pre_repair_hash_available
|
|
999
|
-
and
|
|
1090
|
+
and repair_snapshot.diff_hash_available
|
|
1000
1091
|
and bool(pre_repair_hash)
|
|
1001
|
-
and bool(
|
|
1092
|
+
and bool(repair_snapshot.diff_hash)
|
|
1002
1093
|
)
|
|
1003
|
-
current_diff_hash =
|
|
1004
|
-
current_diff_hash_available =
|
|
1094
|
+
current_diff_hash = repair_snapshot.diff_hash
|
|
1095
|
+
current_diff_hash_available = repair_snapshot.diff_hash_available
|
|
1005
1096
|
if not cross_run_fingerprints_available and current_snapshot.base_sha and pre_repair_files is not None:
|
|
1006
1097
|
exact_diff_fingerprints = [
|
|
1007
1098
|
_get_exact_diff_fingerprint(
|
|
@@ -1013,7 +1104,7 @@ def run_pipeline(
|
|
|
1013
1104
|
)
|
|
1014
1105
|
for head_sha, expected_files in (
|
|
1015
1106
|
(pre_repair_head_sha, pre_repair_files),
|
|
1016
|
-
(
|
|
1107
|
+
(repair_snapshot.head_sha, repair_snapshot.files),
|
|
1017
1108
|
)
|
|
1018
1109
|
]
|
|
1019
1110
|
if all(exact_diff_fingerprints):
|
|
@@ -1025,19 +1116,19 @@ def run_pipeline(
|
|
|
1025
1116
|
guard_blocked = True
|
|
1026
1117
|
guard_block_reason = (
|
|
1027
1118
|
f"PR #{current_snapshot.pr_number}: post-repair diff validation blocked "
|
|
1028
|
-
f"(pre-repair HEAD={pre_repair_head_sha}, post-repair HEAD={
|
|
1029
|
-
f"base={current_snapshot.base_branch}, changed-file count={len(
|
|
1119
|
+
f"(pre-repair HEAD={pre_repair_head_sha}, post-repair HEAD={repair_snapshot.head_sha}, "
|
|
1120
|
+
f"base={current_snapshot.base_branch}, changed-file count={len(repair_snapshot.files)}, "
|
|
1030
1121
|
"missing files=<unavailable>; pre-repair file inventory unavailable)"
|
|
1031
1122
|
)
|
|
1032
1123
|
logger.error(guard_block_reason)
|
|
1033
1124
|
pre_repair_head_sha = ""
|
|
1034
1125
|
baseline_files = (
|
|
1035
|
-
pre_repair_files if pre_repair_files is not None else (
|
|
1126
|
+
pre_repair_files if pre_repair_files is not None else (repair_snapshot.files or ["<pre-repair-diff>"])
|
|
1036
1127
|
)
|
|
1037
1128
|
if pre_repair_head_sha:
|
|
1038
1129
|
cross_run_check = validate_diff_preservation(
|
|
1039
1130
|
pre_files=baseline_files,
|
|
1040
|
-
post_files=
|
|
1131
|
+
post_files=repair_snapshot.files,
|
|
1041
1132
|
pre_hash=pre_repair_hash,
|
|
1042
1133
|
post_hash=current_diff_hash,
|
|
1043
1134
|
pre_hash_available=pre_repair_hash_available and bool(current_snapshot.base_sha),
|
|
@@ -1045,7 +1136,7 @@ def run_pipeline(
|
|
|
1045
1136
|
fingerprint_supported=True,
|
|
1046
1137
|
intentional_noop=False,
|
|
1047
1138
|
pre_head_sha=pre_repair_head_sha,
|
|
1048
|
-
post_head_sha=
|
|
1139
|
+
post_head_sha=repair_snapshot.head_sha,
|
|
1049
1140
|
pre_base_branch=current_snapshot.base_branch,
|
|
1050
1141
|
post_base_branch=current_snapshot.base_branch,
|
|
1051
1142
|
pre_base_sha=current_snapshot.base_sha,
|
|
@@ -1056,8 +1147,8 @@ def run_pipeline(
|
|
|
1056
1147
|
guard_blocked = True
|
|
1057
1148
|
guard_block_reason = (
|
|
1058
1149
|
f"PR #{current_snapshot.pr_number}: post-repair diff validation blocked "
|
|
1059
|
-
f"(pre-repair HEAD={pre_repair_head_sha}, post-repair HEAD={
|
|
1060
|
-
f"base={current_snapshot.base_branch}, changed-file count={len(
|
|
1150
|
+
f"(pre-repair HEAD={pre_repair_head_sha}, post-repair HEAD={repair_snapshot.head_sha}, "
|
|
1151
|
+
f"base={current_snapshot.base_branch}, changed-file count={len(repair_snapshot.files)}, "
|
|
1061
1152
|
f"missing files={missing}; {cross_run_check.reason})"
|
|
1062
1153
|
)
|
|
1063
1154
|
logger.error(guard_block_reason)
|
|
@@ -411,6 +411,10 @@ class CIPlatformProvider(ABC):
|
|
|
411
411
|
"""Return changed files compared with the base, when supported."""
|
|
412
412
|
return None
|
|
413
413
|
|
|
414
|
+
def list_pr_commits(self, pr_number: int) -> list[dict[str, Any]]:
|
|
415
|
+
"""Return PR commits oldest first, including ``sha`` and ``parents``."""
|
|
416
|
+
raise NotImplementedError(f"{type(self).__name__} does not implement list_pr_commits")
|
|
417
|
+
|
|
414
418
|
@abstractmethod
|
|
415
419
|
def list_review_comments(self, pr_number: int, review_id: int) -> list[ReviewCommentInfo]:
|
|
416
420
|
"""List inline comments from a specific review.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
agentic_devtools/__init__.py,sha256=J_Zw_vWKghk-cLmqI83hXQmSiS8zMhGIHM5WPLDkZuo,242
|
|
2
|
-
agentic_devtools/_version.py,sha256=
|
|
2
|
+
agentic_devtools/_version.py,sha256=H2VpPdW7WdQH-H0NmkEpI-HIQN4oeYF9KCyJIqty95E,524
|
|
3
3
|
agentic_devtools/agdt_gitignore.py,sha256=vVVqTjBZ_ijn6U3Lnh_JGrARLschYVN-fFal9jDk0Ak,2694
|
|
4
4
|
agentic_devtools/background_tasks.py,sha256=sFgmqOnCdCjclABJ8V__yDwBXDyi45b1Z-MVv3G2zB8,17664
|
|
5
5
|
agentic_devtools/config.py,sha256=DEVxTVZhsQbVQwO9qdB_1h19aBpjMzF6xJY_ePYLGLs,15629
|
|
@@ -179,12 +179,12 @@ agentic_devtools/cli/ci/dispatcher_throttle.py,sha256=urJQ_jUkSdx4mtWxrKrzbPdDd_
|
|
|
179
179
|
agentic_devtools/cli/ci/due_probe_wakeup.py,sha256=qUSgDbtZ09jytNt6UbCFrwxCoeUObKx6u5W0GQXYeNs,13343
|
|
180
180
|
agentic_devtools/cli/ci/exceptions.py,sha256=zpKWOgnBbHHQgAQRvdRW4VFnE_qdgqgmo8r1H-x47l4,1086
|
|
181
181
|
agentic_devtools/cli/ci/finalization_state.py,sha256=UasYfCuLmm-4e2pNmDwgGzC7mNr8B6frJH8o6dAlGPM,7157
|
|
182
|
-
agentic_devtools/cli/ci/github_provider.py,sha256=
|
|
182
|
+
agentic_devtools/cli/ci/github_provider.py,sha256=wBTpgrrnnkIv6FZx0VemEgLnPnTzcqMS4TVkb3gBGh0,402056
|
|
183
183
|
agentic_devtools/cli/ci/guards.py,sha256=ehy3urO_utrpBa2d5FsqwkJFnlWHG718a1uGhHFTF3c,56984
|
|
184
184
|
agentic_devtools/cli/ci/job_logs.py,sha256=du0-DiNGNxyg2J5YwlFPJ0VW9Ib8eNcwzlia0RCd9SY,12810
|
|
185
185
|
agentic_devtools/cli/ci/logging_config.py,sha256=Tw_h8LB709gbMd0WZMATLAPIJ1r_c_nE18Bi4bvldHA,2340
|
|
186
186
|
agentic_devtools/cli/ci/models.py,sha256=jc7-j7T4plMvw6KuytASQTJwup-VBRgP3sKh3NY7RtY,20535
|
|
187
|
-
agentic_devtools/cli/ci/provider.py,sha256=
|
|
187
|
+
agentic_devtools/cli/ci/provider.py,sha256=ao5j7I0Oaxy7lslgQVscvxl904RmDBMhUPXSfsQXAPM,50260
|
|
188
188
|
agentic_devtools/cli/ci/push_attribution.py,sha256=BcG5p1OAbdE_LrX8w7dKNHsXI2RchP4z5T6ObxOHfRI,4276
|
|
189
189
|
agentic_devtools/cli/ci/repair_prompt.py,sha256=KnNyDRuTmDyDUP7M47FDPZeREmZMFlri8Yntkb38pEU,3241
|
|
190
190
|
agentic_devtools/cli/ci/retry.py,sha256=z5LCO0vRHwvuc7k7fCY25uonq51EX3szQRq-3BXzOF4,8657
|
|
@@ -218,7 +218,7 @@ agentic_devtools/cli/ci/pipeline/exclusion.py,sha256=mrOG5G1-m3U-GM4YgtMTuzmoj02
|
|
|
218
218
|
agentic_devtools/cli/ci/pipeline/gate_verdict.py,sha256=PGxb9Z540ki-i-tJAn-ezcISKHizR16hIXfnVbbZvMQ,44516
|
|
219
219
|
agentic_devtools/cli/ci/pipeline/models.py,sha256=6YpK9_Ezoc4yIhqz4EZr3m32Mxd1f0NSNOoEK-_yJU4,3678
|
|
220
220
|
agentic_devtools/cli/ci/pipeline/repair_attempts.py,sha256=K0L7AIu_Ob_bP-m7G5KDikJDxP9Jx4Z9vh5O5AFUBPw,9727
|
|
221
|
-
agentic_devtools/cli/ci/pipeline/runner.py,sha256
|
|
221
|
+
agentic_devtools/cli/ci/pipeline/runner.py,sha256=qV1ZziehdoHRSXQllIeet4mXVYU7fCAwbpkVN6WQRME,85540
|
|
222
222
|
agentic_devtools/cli/ci/pipeline/session_detector.py,sha256=hXFoNW4J9pM1J_g5_7YXAeyol4PKGRIChzqHSZnxspM,15181
|
|
223
223
|
agentic_devtools/cli/ci/pipeline/snapshot.py,sha256=Qc-H_ko6K2LgzoNVkZxMgHrJ6BoufPEl_616lDZfFhA,54137
|
|
224
224
|
agentic_devtools/cli/ci/pipeline/suggestions.py,sha256=s2FB-y1gd73R3P_5X2CSQJfZPWO5QFU2jFGYB25ZZuY,26965
|
|
@@ -1160,8 +1160,8 @@ agentic_devtools/_bundled_skills/skills/speckit-plan/SKILL.md,sha256=qYLpzgLCIZ6
|
|
|
1160
1160
|
agentic_devtools/_bundled_skills/skills/speckit-specify/SKILL.md,sha256=d9FkeZpBhQKt6aWUggtFA3Vqt4pZqYmTcSkfAANSPA8,11820
|
|
1161
1161
|
agentic_devtools/_bundled_skills/skills/write-github-commit-message/SKILL.md,sha256=Ep1lR8NDN117Iytj172VZgqazFiLpJ56Z7RXgaTnxR8,2626
|
|
1162
1162
|
agentic_devtools/_bundled_skills/skills/write-github-commit-message/commit-types.md,sha256=bTy_t68ZD6R87rFIzq9wybTu8Wudoahb7nB9IWC4bFo,1839
|
|
1163
|
-
agentic_devtools-0.2.
|
|
1164
|
-
agentic_devtools-0.2.
|
|
1165
|
-
agentic_devtools-0.2.
|
|
1166
|
-
agentic_devtools-0.2.
|
|
1167
|
-
agentic_devtools-0.2.
|
|
1163
|
+
agentic_devtools-0.2.549.dist-info/METADATA,sha256=SgAlcrdIYSb1HuV3wO4MPoLN8yQ02Fzn13rFGNZnOeM,35289
|
|
1164
|
+
agentic_devtools-0.2.549.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
1165
|
+
agentic_devtools-0.2.549.dist-info/entry_points.txt,sha256=11ytXmK_Q96uiQI7p9UVP_UVcD_wSJDbfCbGK7IIQDA,13373
|
|
1166
|
+
agentic_devtools-0.2.549.dist-info/licenses/LICENSE,sha256=yBEDdICksxhBYLWoERKp9MTqwGnUF6Ryj9BTLwXTc6k,1082
|
|
1167
|
+
agentic_devtools-0.2.549.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|