devlyn-cli 2.10.1 → 3.0.0
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.
- package/AGENTS.md +4 -9
- package/CLAUDE.md +11 -15
- package/README.md +31 -7
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.json +25 -0
- package/benchmark/auto-resolve/results/20260507-f10-f11-tier1-full-pipeline/headroom-gate.md +10 -0
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260508-f22-exact-error-headroom/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260508-f26-headroom/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F16-cli-quote-tax-rules/l2_risk_probes/result.json +28 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F23-cli-fulfillment-wave/l2_risk_probes/result.json +28 -0
- package/benchmark/auto-resolve/results/20260510-f16-f23-f25-combined-proof/F25-cli-cart-promotion-rules/l2_risk_probes/result.json +30 -0
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f12-webhook-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f15-concurrency-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/F21-cli-scheduler-priority/l2_risk_probes/result.json +32 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.json +44 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/full-pipeline-pair-gate.md +16 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.json +18 -0
- package/benchmark/auto-resolve/results/20260511-f21-current-riskprobes-v1/headroom-gate.md +9 -0
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260511-f3-http-error-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f2-medium-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f31-seat-rebalance-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f32-subscription-renewal-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f4-web-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f5-fixloop-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f6-checksum-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f7-scope-headroom/headroom-gate.md +15 -0
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.json +28 -0
- package/benchmark/auto-resolve/results/20260512-f9-e2e-headroom/headroom-gate.md +15 -0
- package/bin/devlyn.js +6 -1
- package/config/skills/_shared/.ruff.toml +2 -0
- package/config/skills/_shared/adapters/claude.md +9 -1
- package/config/skills/_shared/adapters/codex.md +5 -0
- package/config/skills/_shared/adapters/grok.md +4 -2
- package/config/skills/_shared/archive_run.py +738 -56
- package/config/skills/_shared/codex-config.md +19 -4
- package/config/skills/_shared/codex-monitored.sh +81 -12
- package/config/skills/_shared/collect-codex-findings.py +311 -128
- package/config/skills/_shared/engine-preflight.md +8 -7
- package/config/skills/_shared/expected.schema.json +61 -0
- package/config/skills/_shared/finish-gate.py +12 -11
- package/config/skills/_shared/grok-anchor-guard.py +18 -1
- package/config/skills/_shared/invocation-receipt.py +1041 -0
- package/config/skills/_shared/judge-output-parser.py +200 -0
- package/config/skills/_shared/judge-role-evidence.py +273 -0
- package/config/skills/_shared/process-evidence.py +909 -0
- package/config/skills/_shared/resolve-bootstrap.py +776 -84
- package/config/skills/_shared/resolve-stop-hook.py +33 -1
- package/config/skills/_shared/role-config.py +552 -0
- package/config/skills/_shared/run-bounded.py +1 -1
- package/config/skills/_shared/spec-verify-check.py +749 -181
- package/config/skills/_shared/state-phase-write.py +1838 -58
- package/config/skills/_shared/terminal-claim-check.py +15 -0
- package/config/skills/_shared/verify-merge-findings.py +958 -51
- package/config/skills/devlyn:engines/SKILL.md +8 -16
- package/config/skills/devlyn:ideate/references/spec-template.md +1 -0
- package/config/skills/devlyn:queue/SKILL.md +7 -4
- package/config/skills/devlyn:resolve/SKILL.md +91 -33
- package/config/skills/devlyn:resolve/references/outer-loop.md +15 -0
- package/config/skills/devlyn:resolve/references/phases/build-gate.md +31 -2
- package/config/skills/devlyn:resolve/references/phases/implement.md +3 -2
- package/config/skills/devlyn:resolve/references/phases/verify.md +120 -84
- package/config/skills/devlyn:resolve/references/state-schema.md +22 -8
- package/package.json +5 -1
- package/scripts/lint-skills.sh +314 -285
|
@@ -277,13 +277,11 @@ def run_gate(work: pathlib.Path, devlyn_dir: pathlib.Path) -> int:
|
|
|
277
277
|
return 0
|
|
278
278
|
|
|
279
279
|
findings: list[dict] = []
|
|
280
|
-
failed = False
|
|
281
280
|
reverted = 0
|
|
282
281
|
revert_failed = 0
|
|
283
282
|
for seq, path in enumerate(offenders, start=1):
|
|
284
283
|
ok, detail, existed_at_base = revert_offender(work, base_sha, path)
|
|
285
284
|
status = "reverted" if ok else "revert-failed"
|
|
286
|
-
failed = failed or not ok
|
|
287
285
|
if ok:
|
|
288
286
|
reverted += 1
|
|
289
287
|
else:
|
|
@@ -305,7 +303,10 @@ def run_gate(work: pathlib.Path, devlyn_dir: pathlib.Path) -> int:
|
|
|
305
303
|
),
|
|
306
304
|
))
|
|
307
305
|
write_findings(devlyn_dir, findings)
|
|
308
|
-
|
|
306
|
+
# Exit 0 let a real run treat reverted orchestrator commits as a clean pass.
|
|
307
|
+
# Any offender is therefore unclean even when every automatic revert succeeds;
|
|
308
|
+
# the caller maps exit 1/2 to BLOCKED:finish-gate-unclean.
|
|
309
|
+
exit_code = 2
|
|
309
310
|
write_summary(devlyn_dir, {
|
|
310
311
|
"mode": state.get("mode"),
|
|
311
312
|
"checked": len(checked),
|
|
@@ -386,25 +387,25 @@ def self_test() -> int:
|
|
|
386
387
|
|
|
387
388
|
work, devlyn, _base = make_fixture(root, "tracked-mutation")
|
|
388
389
|
write_text(work / "notes.txt", "polluted\n")
|
|
389
|
-
assert checked_run_gate(work, devlyn) ==
|
|
390
|
+
assert checked_run_gate(work, devlyn) == 2
|
|
390
391
|
assert (work / "notes.txt").read_text(encoding="utf-8") == "base notes\n"
|
|
391
392
|
findings = read_findings(devlyn)
|
|
392
393
|
assert findings[0]["rule_id"] == "scope.finish-unaudited-file"
|
|
393
394
|
assert findings[0]["status"] == "reverted"
|
|
394
395
|
assert_summary(devlyn, {
|
|
395
396
|
"mode": "full", "checked": 1, "offenders": 1,
|
|
396
|
-
"reverted": 1, "revert_failed": 0, "exit":
|
|
397
|
+
"reverted": 1, "revert_failed": 0, "exit": 2,
|
|
397
398
|
})
|
|
398
399
|
|
|
399
400
|
work, devlyn, _base = make_fixture(root, "added-file")
|
|
400
401
|
write_text(work / "runtime.txt", "late\n")
|
|
401
402
|
git_check(work, "add", "runtime.txt")
|
|
402
|
-
assert checked_run_gate(work, devlyn) ==
|
|
403
|
+
assert checked_run_gate(work, devlyn) == 2
|
|
403
404
|
assert not (work / "runtime.txt").exists()
|
|
404
405
|
assert "runtime.txt" not in git_check(work, "diff", "--name-only", _base).splitlines()
|
|
405
406
|
assert_summary(devlyn, {
|
|
406
407
|
"mode": "full", "checked": 1, "offenders": 1,
|
|
407
|
-
"reverted": 1, "revert_failed": 0, "exit":
|
|
408
|
+
"reverted": 1, "revert_failed": 0, "exit": 2,
|
|
408
409
|
})
|
|
409
410
|
|
|
410
411
|
work, devlyn, _base = make_fixture(root, "devlyn-owned-tracked-mutation")
|
|
@@ -414,7 +415,7 @@ def self_test() -> int:
|
|
|
414
415
|
git_check(work, "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-q", "-m", "track devlyn state")
|
|
415
416
|
write_text(archived, "mutated devlyn state\n")
|
|
416
417
|
write_text(work / "notes.txt", "polluted\n")
|
|
417
|
-
assert checked_run_gate(work, devlyn) ==
|
|
418
|
+
assert checked_run_gate(work, devlyn) == 2
|
|
418
419
|
assert archived.read_text(encoding="utf-8") == "mutated devlyn state\n"
|
|
419
420
|
assert (work / "notes.txt").read_text(encoding="utf-8") == "base notes\n"
|
|
420
421
|
findings = read_findings(devlyn)
|
|
@@ -422,7 +423,7 @@ def self_test() -> int:
|
|
|
422
423
|
assert findings[0]["status"] == "reverted"
|
|
423
424
|
assert_summary(devlyn, {
|
|
424
425
|
"mode": "full", "checked": 1, "offenders": 1,
|
|
425
|
-
"reverted": 1, "revert_failed": 0, "exit":
|
|
426
|
+
"reverted": 1, "revert_failed": 0, "exit": 2,
|
|
426
427
|
})
|
|
427
428
|
|
|
428
429
|
work, devlyn, base = make_fixture(root, "cleanup-window")
|
|
@@ -469,12 +470,12 @@ def self_test() -> int:
|
|
|
469
470
|
|
|
470
471
|
work, devlyn, _base = make_fixture(root, "deleted-file")
|
|
471
472
|
(work / "notes.txt").unlink()
|
|
472
|
-
assert checked_run_gate(work, devlyn) ==
|
|
473
|
+
assert checked_run_gate(work, devlyn) == 2
|
|
473
474
|
assert (work / "notes.txt").read_text(encoding="utf-8") == "base notes\n"
|
|
474
475
|
assert read_findings(devlyn)[0]["status"] == "reverted"
|
|
475
476
|
assert_summary(devlyn, {
|
|
476
477
|
"mode": "full", "checked": 1, "offenders": 1,
|
|
477
|
-
"reverted": 1, "revert_failed": 0, "exit":
|
|
478
|
+
"reverted": 1, "revert_failed": 0, "exit": 2,
|
|
478
479
|
})
|
|
479
480
|
|
|
480
481
|
work, devlyn, _base = make_fixture(root, "git-diff-failure")
|
|
@@ -33,9 +33,26 @@ SHELL_TOOLS = {"run_terminal_command", "run_terminal_cmd", "Bash"}
|
|
|
33
33
|
FORBIDDEN = set(";&|`$()<>") | {"\n", "\r"}
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def reject_json_constant(token):
|
|
37
|
+
raise ValueError(f"invalid JSON numeric constant: {token}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def reject_duplicate_keys(pairs):
|
|
41
|
+
result = {}
|
|
42
|
+
for key, value in pairs:
|
|
43
|
+
if key in result:
|
|
44
|
+
raise ValueError(f"duplicate JSON key: {key}")
|
|
45
|
+
result[key] = value
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
|
|
36
49
|
def main():
|
|
37
50
|
anchor = os.environ.get("DEVLYN_PROBE_ANCHOR", "")
|
|
38
|
-
payload = json.load(
|
|
51
|
+
payload = json.load(
|
|
52
|
+
sys.stdin,
|
|
53
|
+
parse_constant=reject_json_constant,
|
|
54
|
+
object_pairs_hook=reject_duplicate_keys,
|
|
55
|
+
)
|
|
39
56
|
|
|
40
57
|
if payload.get("toolName") not in SHELL_TOOLS or not anchor:
|
|
41
58
|
print(json.dumps({"decision": "allow"}))
|