agentic-devtools 0.2.575__py3-none-any.whl → 0.2.577__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/checks/smart_module_tests.py +11 -0
- agentic_devtools/cli/ci/pipeline/conflict_reconciliation.py +308 -0
- {agentic_devtools-0.2.575.dist-info → agentic_devtools-0.2.577.dist-info}/METADATA +1 -1
- {agentic_devtools-0.2.575.dist-info → agentic_devtools-0.2.577.dist-info}/RECORD +8 -7
- {agentic_devtools-0.2.575.dist-info → agentic_devtools-0.2.577.dist-info}/WHEEL +0 -0
- {agentic_devtools-0.2.575.dist-info → agentic_devtools-0.2.577.dist-info}/entry_points.txt +0 -0
- {agentic_devtools-0.2.575.dist-info → agentic_devtools-0.2.577.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.577'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 577)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -44,6 +44,17 @@ _MODULE_SPECS = {
|
|
|
44
44
|
"tasks": _ModuleTestSpec(("tests/unit/cli/tasks",), (), ("agentic_devtools/cli/tasks",)),
|
|
45
45
|
"github_module": _ModuleTestSpec(("tests/unit/cli/github",), (), ("agentic_devtools/cli/github",)),
|
|
46
46
|
"copilot": _ModuleTestSpec(("tests/unit/cli/copilot",), (), ("agentic_devtools/cli/copilot",)),
|
|
47
|
+
"ci": _ModuleTestSpec(
|
|
48
|
+
(
|
|
49
|
+
"tests/unit/cli/ci/critique_adjudicator/test_critique_adjudicator.py",
|
|
50
|
+
"tests/unit/cli/ci/pipeline/critique_gate/test_critique_gate_exception_passed.py",
|
|
51
|
+
),
|
|
52
|
+
(),
|
|
53
|
+
(
|
|
54
|
+
"agentic_devtools.cli.ci.critique_adjudicator",
|
|
55
|
+
"agentic_devtools.cli.ci.pipeline.critique_gate",
|
|
56
|
+
),
|
|
57
|
+
),
|
|
47
58
|
"speckit": _ModuleTestSpec(("tests/unit/cli/speckit",), (), ("agentic_devtools/cli/speckit",)),
|
|
48
59
|
"azure": _ModuleTestSpec(("tests/unit/cli/azure",), (), ("agentic_devtools/cli/azure",)),
|
|
49
60
|
"issue_template": _ModuleTestSpec(("tests/unit/cli/issue_template",), (), ("agentic_devtools/cli/issue_template",)),
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""Versioned reconciliation claims, not authentication or a merge authorization.
|
|
2
|
+
|
|
3
|
+
All identities, digests, inventories, and verdicts here are unverified payload
|
|
4
|
+
data. Provider verification, original-criteria digest verification, live-head
|
|
5
|
+
binding, and every independent pipeline gate remain the caller's responsibility.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import base64
|
|
11
|
+
import binascii
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
from dataclasses import asdict, dataclass, fields
|
|
16
|
+
from typing import Any, Literal
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"ReconciliationAttestation",
|
|
20
|
+
"ReconciliationCriterionVerdict",
|
|
21
|
+
"ReconciliationFileVerdict",
|
|
22
|
+
"ReconciliationValidationError",
|
|
23
|
+
"validate_reconciliation_attestation",
|
|
24
|
+
"encode_reconciliation_review_body",
|
|
25
|
+
"decode_reconciliation_review_body",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
_LOGIN = r"[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){0,38}"
|
|
29
|
+
_CRITERIA_SOURCE = "https://github.com/swai-factory/agentic-devtools/issues/4299#acceptance-and-safety-tests"
|
|
30
|
+
_CRITERION_IDS = ("AC1", "AC2", "AC3", "AC4", "AC5", "AC6", "AC7")
|
|
31
|
+
_MAX_BODY_LENGTH = 58_000
|
|
32
|
+
_FOOTER = "<!-- /agdt-reconciliation -->"
|
|
33
|
+
_Verdict = Literal["accepted", "rejected", "unresolved"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class ReconciliationFileVerdict:
|
|
38
|
+
"""Claim about raw file bytes and intended behavior at the reviewed head."""
|
|
39
|
+
|
|
40
|
+
path: str
|
|
41
|
+
content_sha256: str
|
|
42
|
+
verdict: _Verdict
|
|
43
|
+
behavior: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class ReconciliationCriterionVerdict:
|
|
48
|
+
"""Claim about one original parent acceptance criterion."""
|
|
49
|
+
|
|
50
|
+
criterion_id: str
|
|
51
|
+
verdict: _Verdict
|
|
52
|
+
rationale: str
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True)
|
|
56
|
+
class ReconciliationAttestation:
|
|
57
|
+
"""Immutable schema-v1 claims with separate repair-output and reviewed heads."""
|
|
58
|
+
|
|
59
|
+
schema_version: int
|
|
60
|
+
repository: str
|
|
61
|
+
pr_number: int
|
|
62
|
+
pre_repair_sha: str
|
|
63
|
+
pinned_base_sha: str
|
|
64
|
+
repair_output_sha: str
|
|
65
|
+
reviewed_head_sha: str
|
|
66
|
+
changed_files: tuple[str, ...]
|
|
67
|
+
file_verdicts: tuple[ReconciliationFileVerdict, ...]
|
|
68
|
+
criteria_source: str
|
|
69
|
+
criteria_source_sha256: str
|
|
70
|
+
criterion_verdicts: tuple[ReconciliationCriterionVerdict, ...]
|
|
71
|
+
provider_evidence_ref: str
|
|
72
|
+
configured_approver_login: str
|
|
73
|
+
reviewer_login: str
|
|
74
|
+
repair_writer_login: str
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ReconciliationValidationError(ValueError):
|
|
78
|
+
"""Contract failure with a stable machine-readable reason."""
|
|
79
|
+
|
|
80
|
+
def __init__(self, reason: str) -> None:
|
|
81
|
+
self.reason = reason
|
|
82
|
+
super().__init__(reason)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _require_pattern(value: str, pattern: str, reason: str) -> None:
|
|
86
|
+
"""Require a string matching the entire ASCII contract pattern."""
|
|
87
|
+
if not isinstance(value, str) or re.fullmatch(pattern, value) is None:
|
|
88
|
+
raise ReconciliationValidationError(reason)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _validate_path(path: str) -> None:
|
|
92
|
+
"""Validate a repository-relative Git path without normalization."""
|
|
93
|
+
if (
|
|
94
|
+
not isinstance(path, str)
|
|
95
|
+
or not path
|
|
96
|
+
or path.startswith("/")
|
|
97
|
+
or re.match(r"[A-Za-z]:/", path) is not None
|
|
98
|
+
or "\\" in path
|
|
99
|
+
or "\0" in path
|
|
100
|
+
or any(segment in ("", ".", "..") for segment in path.split("/"))
|
|
101
|
+
):
|
|
102
|
+
raise ReconciliationValidationError("invalid_file_path")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def validate_reconciliation_attestation(attestation: ReconciliationAttestation) -> None:
|
|
106
|
+
"""Validate payload structure and consistency only; never authorize a repair."""
|
|
107
|
+
if type(attestation) is not ReconciliationAttestation:
|
|
108
|
+
raise ReconciliationValidationError("invalid_record_type")
|
|
109
|
+
if type(attestation.schema_version) is not int or attestation.schema_version != 1:
|
|
110
|
+
raise ReconciliationValidationError("unsupported_schema_version")
|
|
111
|
+
_require_pattern(attestation.repository, rf"{_LOGIN}/[a-z0-9._-]{{1,100}}", "invalid_repository")
|
|
112
|
+
if type(attestation.pr_number) is not int or attestation.pr_number <= 0:
|
|
113
|
+
raise ReconciliationValidationError("invalid_pr_number")
|
|
114
|
+
for sha in (
|
|
115
|
+
attestation.pre_repair_sha,
|
|
116
|
+
attestation.pinned_base_sha,
|
|
117
|
+
attestation.repair_output_sha,
|
|
118
|
+
attestation.reviewed_head_sha,
|
|
119
|
+
):
|
|
120
|
+
_require_pattern(sha, r"[0-9a-f]{40}", "invalid_commit_sha")
|
|
121
|
+
_require_pattern(attestation.criteria_source_sha256, r"[0-9a-f]{64}", "invalid_sha256")
|
|
122
|
+
if attestation.criteria_source != _CRITERIA_SOURCE:
|
|
123
|
+
raise ReconciliationValidationError("criterion_coverage_mismatch")
|
|
124
|
+
_validate_identities(attestation)
|
|
125
|
+
for collection in (attestation.changed_files, attestation.file_verdicts, attestation.criterion_verdicts):
|
|
126
|
+
if type(collection) is not tuple:
|
|
127
|
+
raise ReconciliationValidationError("invalid_collection_type")
|
|
128
|
+
_validate_files(attestation)
|
|
129
|
+
_validate_criteria(attestation.criterion_verdicts)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _validate_identities(attestation: ReconciliationAttestation) -> None:
|
|
133
|
+
"""Check claimed login and locator consistency, not provider identity."""
|
|
134
|
+
for login in (
|
|
135
|
+
attestation.configured_approver_login,
|
|
136
|
+
attestation.reviewer_login,
|
|
137
|
+
attestation.repair_writer_login,
|
|
138
|
+
):
|
|
139
|
+
_require_pattern(login, _LOGIN, "invalid_login")
|
|
140
|
+
if attestation.reviewer_login != attestation.configured_approver_login:
|
|
141
|
+
raise ReconciliationValidationError("reviewer_not_configured_approver")
|
|
142
|
+
if attestation.reviewer_login == attestation.repair_writer_login:
|
|
143
|
+
raise ReconciliationValidationError("reviewer_is_repair_writer")
|
|
144
|
+
expected_ref = f"github://{attestation.repository}/pull/{attestation.pr_number}/reviews"
|
|
145
|
+
if attestation.provider_evidence_ref != expected_ref:
|
|
146
|
+
raise ReconciliationValidationError("invalid_provider_evidence_ref")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _require_inventory(values: tuple[str, ...], duplicate_reason: str) -> None:
|
|
150
|
+
"""Require unique identifiers in lexicographic order."""
|
|
151
|
+
if len(set(values)) != len(values):
|
|
152
|
+
raise ReconciliationValidationError(duplicate_reason)
|
|
153
|
+
if tuple(sorted(values)) != values:
|
|
154
|
+
raise ReconciliationValidationError("noncanonical_order")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _validate_files(attestation: ReconciliationAttestation) -> None:
|
|
158
|
+
"""Require exact, accepted, behavior-described coverage of the claimed inventory."""
|
|
159
|
+
if not attestation.changed_files:
|
|
160
|
+
raise ReconciliationValidationError("file_inventory_empty")
|
|
161
|
+
for path in attestation.changed_files:
|
|
162
|
+
_validate_path(path)
|
|
163
|
+
_require_inventory(attestation.changed_files, "duplicate_file")
|
|
164
|
+
for file_record in attestation.file_verdicts:
|
|
165
|
+
_validate_file_record(file_record)
|
|
166
|
+
file_paths = tuple(record.path for record in attestation.file_verdicts)
|
|
167
|
+
_require_inventory(file_paths, "duplicate_file")
|
|
168
|
+
if file_paths != attestation.changed_files:
|
|
169
|
+
raise ReconciliationValidationError("file_verdict_coverage_mismatch")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _validate_file_record(file_record: ReconciliationFileVerdict) -> None:
|
|
173
|
+
"""Require a structurally valid accepted file claim."""
|
|
174
|
+
if type(file_record) is not ReconciliationFileVerdict:
|
|
175
|
+
raise ReconciliationValidationError("invalid_record_type")
|
|
176
|
+
_validate_path(file_record.path)
|
|
177
|
+
_require_pattern(file_record.content_sha256, r"[0-9a-f]{64}", "invalid_sha256")
|
|
178
|
+
if file_record.verdict not in ("accepted", "rejected", "unresolved"):
|
|
179
|
+
raise ReconciliationValidationError("invalid_file_verdict")
|
|
180
|
+
if file_record.verdict != "accepted":
|
|
181
|
+
raise ReconciliationValidationError(f"file_verdict_{file_record.verdict}")
|
|
182
|
+
if not isinstance(file_record.behavior, str) or not file_record.behavior.strip():
|
|
183
|
+
raise ReconciliationValidationError("empty_file_behavior")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _validate_criteria(records: tuple[ReconciliationCriterionVerdict, ...]) -> None:
|
|
187
|
+
"""Require accepted claims covering all seven original criterion IDs."""
|
|
188
|
+
for criterion_record in records:
|
|
189
|
+
if type(criterion_record) is not ReconciliationCriterionVerdict:
|
|
190
|
+
raise ReconciliationValidationError("invalid_record_type")
|
|
191
|
+
if criterion_record.criterion_id not in _CRITERION_IDS:
|
|
192
|
+
raise ReconciliationValidationError("criterion_coverage_mismatch")
|
|
193
|
+
if criterion_record.verdict not in ("accepted", "rejected", "unresolved"):
|
|
194
|
+
raise ReconciliationValidationError("invalid_criterion_verdict")
|
|
195
|
+
if criterion_record.verdict != "accepted":
|
|
196
|
+
raise ReconciliationValidationError(f"criterion_verdict_{criterion_record.verdict}")
|
|
197
|
+
if not isinstance(criterion_record.rationale, str) or not criterion_record.rationale.strip():
|
|
198
|
+
raise ReconciliationValidationError("empty_criterion_rationale")
|
|
199
|
+
criterion_ids = tuple(record.criterion_id for record in records)
|
|
200
|
+
_require_inventory(criterion_ids, "duplicate_criterion")
|
|
201
|
+
if criterion_ids != _CRITERION_IDS:
|
|
202
|
+
raise ReconciliationValidationError("criterion_coverage_mismatch")
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _canonical_json(payload: Any) -> bytes:
|
|
206
|
+
"""Serialize canonical ASCII JSON as UTF-8 bytes."""
|
|
207
|
+
return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True, allow_nan=False).encode(
|
|
208
|
+
"utf-8"
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def encode_reconciliation_review_body(attestation: ReconciliationAttestation) -> str:
|
|
213
|
+
"""Encode a complete claim, enforcing the envelope size before field validation."""
|
|
214
|
+
if type(attestation) is not ReconciliationAttestation:
|
|
215
|
+
raise ReconciliationValidationError("invalid_record_type")
|
|
216
|
+
try:
|
|
217
|
+
payload = _canonical_json(asdict(attestation))
|
|
218
|
+
except TypeError, ValueError, RecursionError:
|
|
219
|
+
# Non-JSON caller values have no encodable body to size. Validation
|
|
220
|
+
# supplies their precise reason without coercing the original records.
|
|
221
|
+
validate_reconciliation_attestation(attestation)
|
|
222
|
+
raise ReconciliationValidationError("invalid_record_type") from None
|
|
223
|
+
encoded = base64.urlsafe_b64encode(payload).decode("ascii").rstrip("=")
|
|
224
|
+
digest = hashlib.sha256(payload).hexdigest()
|
|
225
|
+
body = f"<!-- agdt-reconciliation:v1 sha256={digest} -->\n{encoded}\n{_FOOTER}"
|
|
226
|
+
if len(body) > _MAX_BODY_LENGTH:
|
|
227
|
+
raise ReconciliationValidationError("review_body_too_large")
|
|
228
|
+
validate_reconciliation_attestation(attestation)
|
|
229
|
+
return body
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _json_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
233
|
+
"""Reject duplicate keys at every JSON object depth."""
|
|
234
|
+
result: dict[str, Any] = {}
|
|
235
|
+
for key, value in pairs:
|
|
236
|
+
if key in result:
|
|
237
|
+
raise ReconciliationValidationError("invalid_json")
|
|
238
|
+
result[key] = value
|
|
239
|
+
return result
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _record_from_json[Record: ReconciliationAttestation | ReconciliationFileVerdict | ReconciliationCriterionVerdict](
|
|
243
|
+
record_type: type[Record], payload: Any
|
|
244
|
+
) -> Record:
|
|
245
|
+
"""Require the exact key set before constructing a frozen record."""
|
|
246
|
+
if type(payload) is not dict:
|
|
247
|
+
raise ReconciliationValidationError("invalid_record_type")
|
|
248
|
+
expected = {field.name for field in fields(record_type)}
|
|
249
|
+
if payload.keys() - expected:
|
|
250
|
+
raise ReconciliationValidationError("unknown_field")
|
|
251
|
+
if expected - payload.keys():
|
|
252
|
+
raise ReconciliationValidationError("missing_field")
|
|
253
|
+
return record_type(**payload)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _decode_base64url(encoded: str) -> bytes:
|
|
257
|
+
"""Decode strictly unpadded, canonical RFC 4648 URL-safe Base64."""
|
|
258
|
+
if re.fullmatch(r"[A-Za-z0-9_-]+", encoded) is None:
|
|
259
|
+
raise ReconciliationValidationError("invalid_base64url")
|
|
260
|
+
try:
|
|
261
|
+
payload = base64.b64decode(encoded + "=" * (-len(encoded) % 4), altchars=b"-_", validate=True)
|
|
262
|
+
except binascii.Error as exc:
|
|
263
|
+
raise ReconciliationValidationError("invalid_base64url") from exc
|
|
264
|
+
if base64.urlsafe_b64encode(payload).decode("ascii").rstrip("=") != encoded:
|
|
265
|
+
raise ReconciliationValidationError("invalid_base64url")
|
|
266
|
+
return payload
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def decode_reconciliation_review_body(body: str) -> ReconciliationAttestation:
|
|
270
|
+
"""Decode only one exact canonical block; do not authenticate its claims."""
|
|
271
|
+
if not isinstance(body, str):
|
|
272
|
+
raise ReconciliationValidationError("malformed_metadata")
|
|
273
|
+
if len(body) > _MAX_BODY_LENGTH:
|
|
274
|
+
raise ReconciliationValidationError("review_body_too_large")
|
|
275
|
+
lines = body.split("\n")
|
|
276
|
+
if len(lines) != 3:
|
|
277
|
+
raise ReconciliationValidationError("malformed_metadata")
|
|
278
|
+
header = re.fullmatch(r"<!-- agdt-reconciliation:v1 sha256=([0-9a-f]{64}) -->", lines[0])
|
|
279
|
+
if header is None or lines[2] != _FOOTER:
|
|
280
|
+
raise ReconciliationValidationError("malformed_metadata")
|
|
281
|
+
payload = _decode_base64url(lines[1])
|
|
282
|
+
if hashlib.sha256(payload).hexdigest() != header[1]:
|
|
283
|
+
raise ReconciliationValidationError("payload_digest_mismatch")
|
|
284
|
+
try:
|
|
285
|
+
data = json.loads(payload.decode("utf-8"), object_pairs_hook=_json_object)
|
|
286
|
+
canonical = _canonical_json(data)
|
|
287
|
+
except (ValueError, RecursionError) as exc:
|
|
288
|
+
raise ReconciliationValidationError("invalid_json") from exc
|
|
289
|
+
if canonical != payload:
|
|
290
|
+
raise ReconciliationValidationError("noncanonical_payload")
|
|
291
|
+
_record_from_json(ReconciliationAttestation, data)
|
|
292
|
+
record_types: tuple[
|
|
293
|
+
tuple[str, type[ReconciliationFileVerdict] | type[ReconciliationCriterionVerdict] | None], ...
|
|
294
|
+
] = (
|
|
295
|
+
("changed_files", None),
|
|
296
|
+
("file_verdicts", ReconciliationFileVerdict),
|
|
297
|
+
("criterion_verdicts", ReconciliationCriterionVerdict),
|
|
298
|
+
)
|
|
299
|
+
for key, record_type in record_types:
|
|
300
|
+
collection = data[key]
|
|
301
|
+
if type(collection) is not list:
|
|
302
|
+
raise ReconciliationValidationError("invalid_collection_type")
|
|
303
|
+
data[key] = tuple(
|
|
304
|
+
_record_from_json(record_type, record) if record_type is not None else record for record in collection
|
|
305
|
+
)
|
|
306
|
+
attestation = _record_from_json(ReconciliationAttestation, data)
|
|
307
|
+
validate_reconciliation_attestation(attestation)
|
|
308
|
+
return attestation
|
|
@@ -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=TIWdW15l89P8z-XtWYdluJmDXV7ryxUz-CBFY28AsZc,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
|
|
@@ -220,7 +220,7 @@ agentic_devtools/cli/checks/quality_baseline.py,sha256=PbSYAiJdWwEDP8SGGUXNpJVxk
|
|
|
220
220
|
agentic_devtools/cli/checks/setup_drift.py,sha256=bVR0F4wpwt8rOl829tGXKqI1PDUbg9JsXTShgYaJSSM,7666
|
|
221
221
|
agentic_devtools/cli/checks/setup_drift_changed_files.py,sha256=73IuzquyLDKhWderCvFE5TXnHuBxBcQTSbg2p15-wKE,3719
|
|
222
222
|
agentic_devtools/cli/checks/skill_classification.py,sha256=vZGv2IjT-uEMEDguWhdZPyTLB2QD4rTVnATS7Agrjrc,8521
|
|
223
|
-
agentic_devtools/cli/checks/smart_module_tests.py,sha256=
|
|
223
|
+
agentic_devtools/cli/checks/smart_module_tests.py,sha256=wYr_o9ojqQStEA8VfFS0YbBYrwsGNHtfEgoPk2067dk,8063
|
|
224
224
|
agentic_devtools/cli/checks/structure.py,sha256=b6Z_eXoV4D6WU2EDaFBDRTHmHzHYos1dv5pNLTbs80E,1771
|
|
225
225
|
agentic_devtools/cli/checks/tests.py,sha256=ZJoMkTdbo3H2_ojadG3nEOw4xUmUciER4N_2mO_5sUg,5237
|
|
226
226
|
agentic_devtools/cli/checks/xdist_policy.py,sha256=JSb3HijPjpiSV0Gh7PLX4nWc0Bvb2Bi5rAl4Ww8l0NY,1156
|
|
@@ -299,6 +299,7 @@ agentic_devtools/cli/ci/evaluator/snapshot_markdown_blocks.py,sha256=0myRRK4CpYP
|
|
|
299
299
|
agentic_devtools/cli/ci/pipeline/__init__.py,sha256=kVtyTqirPi_pXeEPpa3nYqW15ILPiAVpGGWML3CEl3s,755
|
|
300
300
|
agentic_devtools/cli/ci/pipeline/base.py,sha256=KanjtOEcz6myQPoNqNYO5bsbHL5LPhm-PFnL8yT7Q2M,1268
|
|
301
301
|
agentic_devtools/cli/ci/pipeline/command.py,sha256=f4KfVWkKheIb4xaUbyO9dF1idy5wLR-qPtZHEXy1MQg,12428
|
|
302
|
+
agentic_devtools/cli/ci/pipeline/conflict_reconciliation.py,sha256=H_O67JPHeqByOfsDvKXg9bsN2CIYhMcJpO_xIduEDto,13662
|
|
302
303
|
agentic_devtools/cli/ci/pipeline/critique_gate.py,sha256=OGaaTy_21pbPBvJSNyjTXvxWTAWYLbCSmrKARc4JYaw,3763
|
|
303
304
|
agentic_devtools/cli/ci/pipeline/critique_snapshot.py,sha256=_lJyfCLqeEw9WDMV7qQsYZljgfdDhalhoGtG9Lw0Hvo,9203
|
|
304
305
|
agentic_devtools/cli/ci/pipeline/deferral.py,sha256=M0WSLAJol9xLe1RuWNKiuRAw3EqU8VULDJqUSwM0HCw,19426
|
|
@@ -1288,8 +1289,8 @@ agentic_devtools/_bundled_skills/skills/speckit-plan/SKILL.md,sha256=qYLpzgLCIZ6
|
|
|
1288
1289
|
agentic_devtools/_bundled_skills/skills/speckit-specify/SKILL.md,sha256=HbHRbdphMqbtNw6fL6NcYCj6sSFmUyk2S4U0bZ9p_l4,13681
|
|
1289
1290
|
agentic_devtools/_bundled_skills/skills/write-github-commit-message/SKILL.md,sha256=Ep1lR8NDN117Iytj172VZgqazFiLpJ56Z7RXgaTnxR8,2626
|
|
1290
1291
|
agentic_devtools/_bundled_skills/skills/write-github-commit-message/commit-types.md,sha256=bTy_t68ZD6R87rFIzq9wybTu8Wudoahb7nB9IWC4bFo,1839
|
|
1291
|
-
agentic_devtools-0.2.
|
|
1292
|
-
agentic_devtools-0.2.
|
|
1293
|
-
agentic_devtools-0.2.
|
|
1294
|
-
agentic_devtools-0.2.
|
|
1295
|
-
agentic_devtools-0.2.
|
|
1292
|
+
agentic_devtools-0.2.577.dist-info/METADATA,sha256=UDLYuI2Tr9N_i5CYmG3b1TL9uHo8cntMfnpr8BWPO1E,35393
|
|
1293
|
+
agentic_devtools-0.2.577.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
1294
|
+
agentic_devtools-0.2.577.dist-info/entry_points.txt,sha256=kL35_Y5OHI6XpPneeBTcX82ORjjfx2VIK6XfmKHgNm4,13630
|
|
1295
|
+
agentic_devtools-0.2.577.dist-info/licenses/LICENSE,sha256=yBEDdICksxhBYLWoERKp9MTqwGnUF6Ryj9BTLwXTc6k,1082
|
|
1296
|
+
agentic_devtools-0.2.577.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|