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.
@@ -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.548'
22
- __version_tuple__ = version_tuple = (0, 2, 548)
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 current_snapshot.diff_hash_available
1090
+ and repair_snapshot.diff_hash_available
1000
1091
  and bool(pre_repair_hash)
1001
- and bool(current_snapshot.diff_hash)
1092
+ and bool(repair_snapshot.diff_hash)
1002
1093
  )
1003
- current_diff_hash = current_snapshot.diff_hash
1004
- current_diff_hash_available = current_snapshot.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
- (current_snapshot.head_sha, current_snapshot.files),
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={current_snapshot.head_sha}, "
1029
- f"base={current_snapshot.base_branch}, changed-file count={len(current_snapshot.files)}, "
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 (current_snapshot.files or ["<pre-repair-diff>"])
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=current_snapshot.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=current_snapshot.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={current_snapshot.head_sha}, "
1060
- f"base={current_snapshot.base_branch}, changed-file count={len(current_snapshot.files)}, "
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,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentic-devtools
3
- Version: 0.2.548
3
+ Version: 0.2.549
4
4
  Summary: Agentic devtools integrate Jira, DevOps & more
5
5
  Author: ayaiayorg
6
6
  License-Expression: MIT
@@ -1,5 +1,5 @@
1
1
  agentic_devtools/__init__.py,sha256=J_Zw_vWKghk-cLmqI83hXQmSiS8zMhGIHM5WPLDkZuo,242
2
- agentic_devtools/_version.py,sha256=ojzVDrlWMI2Qvet0wUNekX1OB0rnYRlHIriLBnNB3O8,524
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=KaD_Qv2vvTd1G9OWX8vPuBMdLJzIKxgYOGd6OKj8MKs,401742
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=oUDYz4KvTvRfTQa6bDH4szjEPU2GHZAj25fx48Xr5QE,50012
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=-gnb8uFZQasACG602_NPS8ep7odGbPvzkfu2bhmL3A4,81212
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.548.dist-info/METADATA,sha256=93aYSeGPOHdZz_kryUoGCFNi20b-9jcIRBYN_SzaZ4I,35289
1164
- agentic_devtools-0.2.548.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
1165
- agentic_devtools-0.2.548.dist-info/entry_points.txt,sha256=11ytXmK_Q96uiQI7p9UVP_UVcD_wSJDbfCbGK7IIQDA,13373
1166
- agentic_devtools-0.2.548.dist-info/licenses/LICENSE,sha256=yBEDdICksxhBYLWoERKp9MTqwGnUF6Ryj9BTLwXTc6k,1082
1167
- agentic_devtools-0.2.548.dist-info/RECORD,,
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,,