@antoneeo/mkt-agentic-sdlc-skill 0.12.0 → 0.13.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/CHANGELOG.md +21 -0
- package/README.md +150 -134
- package/gemini-extension.json +1 -1
- package/package.json +4 -2
- package/scripts/init.js +6 -16
- package/skills/mkt-agentic-sdlc/ENFORCEMENT.md +5 -5
- package/skills/mkt-agentic-sdlc/SKILL.md +11 -3
- package/skills/mkt-agentic-sdlc/memory.md +88 -0
- package/skills/mkt-agentic-sdlc/routing.md +7 -1
- package/skills/mkt-agentic-sdlc/scripts/knowledge.py +2089 -0
- package/skills/mkt-agentic-sdlc/scripts/mkt_check.py +718 -734
- package/skills/mkt-agentic-sdlc/scripts/sdlc_core.py +76 -5
|
@@ -569,6 +569,36 @@ def git_changed_since(root, ref, rel_path):
|
|
|
569
569
|
return None
|
|
570
570
|
|
|
571
571
|
|
|
572
|
+
def git_ref_state(root, ref):
|
|
573
|
+
"""Where a recorded commit stands against HEAD (F-056).
|
|
574
|
+
|
|
575
|
+
'ancestor' -- in HEAD's history; 'orphan' -- a commit HEAD's history does not
|
|
576
|
+
contain (amended, rebased or squash-merged away, or marked on another branch:
|
|
577
|
+
it stops resolving once pruned, and on any fresh clone); 'missing' -- not a
|
|
578
|
+
commit in this repository; 'unknown' -- git gave no yes/no answer.
|
|
579
|
+
Callers pass a hash-shaped ref only: that check is what keeps document
|
|
580
|
+
content from reaching git's argv as an option."""
|
|
581
|
+
try:
|
|
582
|
+
r = subprocess.run(["git", "cat-file", "-e", ref + "^{commit}"],
|
|
583
|
+
cwd=str(root), capture_output=True, text=True, timeout=30)
|
|
584
|
+
if r.returncode != 0:
|
|
585
|
+
return "missing"
|
|
586
|
+
r = subprocess.run(["git", "merge-base", "--is-ancestor", ref, "HEAD"],
|
|
587
|
+
cwd=str(root), capture_output=True, text=True, timeout=30)
|
|
588
|
+
except Exception:
|
|
589
|
+
return "unknown"
|
|
590
|
+
return {0: "ancestor", 1: "orphan"}.get(r.returncode, "unknown")
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def git_is_shallow(root):
|
|
594
|
+
try:
|
|
595
|
+
r = subprocess.run(["git", "rev-parse", "--is-shallow-repository"],
|
|
596
|
+
cwd=str(root), capture_output=True, text=True, timeout=10)
|
|
597
|
+
return r.returncode == 0 and r.stdout.strip() == "true"
|
|
598
|
+
except Exception:
|
|
599
|
+
return False
|
|
600
|
+
|
|
601
|
+
|
|
572
602
|
# -------------------------------------------------------------------- index
|
|
573
603
|
|
|
574
604
|
def build_index(root):
|
|
@@ -1543,6 +1573,11 @@ def cmd_stale(root, hybrid=False):
|
|
|
1543
1573
|
"(audit not initialized, or Hybrid mode where mapping is delegated to devPNT).")
|
|
1544
1574
|
return rc # was: return 0 — MUST carry guide rc
|
|
1545
1575
|
use_git = git_available(root)
|
|
1576
|
+
entry = entry_script()
|
|
1577
|
+
# F-056: an ANALYZED row whose reference cannot be evaluated is UNVERIFIED,
|
|
1578
|
+
# never fresh. Each `continue` below that skips such a row records it here;
|
|
1579
|
+
# skipping silently is how a pruned reference printed `[ok]` over three areas.
|
|
1580
|
+
unverifiable = []
|
|
1546
1581
|
stale = []
|
|
1547
1582
|
for row in rows:
|
|
1548
1583
|
if row["status"] != "ANALYZED":
|
|
@@ -1561,16 +1596,42 @@ def cmd_stale(root, hybrid=False):
|
|
|
1561
1596
|
print(f"[warn] {rel}: path does not exist")
|
|
1562
1597
|
continue
|
|
1563
1598
|
changed = []
|
|
1564
|
-
|
|
1599
|
+
remark = f"re-analyze the area, then run: {entry} mark {rel}"
|
|
1600
|
+
if re.fullmatch(r"[0-9a-fA-F]{7,40}", ref or ""):
|
|
1601
|
+
if not use_git:
|
|
1602
|
+
print(f"[stale] {rel}: reference '{ref}' is a git commit, but git is not usable "
|
|
1603
|
+
"here (not a git work tree, git missing, or the repository refused): its "
|
|
1604
|
+
"freshness cannot be evaluated. Run stale inside the git work tree, or "
|
|
1605
|
+
+ remark)
|
|
1606
|
+
unverifiable.append(rel)
|
|
1607
|
+
continue
|
|
1608
|
+
state = git_ref_state(root, ref)
|
|
1609
|
+
if state == "missing":
|
|
1610
|
+
shallow = (" This clone is shallow: full history may hold it "
|
|
1611
|
+
"(git fetch --unshallow)." if git_is_shallow(root) else "")
|
|
1612
|
+
print(f"[stale] {rel}: git ref '{ref}' is not a commit in this repository "
|
|
1613
|
+
"(amended, rebased or squash-merged away and pruned, or never fetched "
|
|
1614
|
+
f"here): its freshness cannot be evaluated.{shallow} To fix, " + remark)
|
|
1615
|
+
unverifiable.append(rel)
|
|
1616
|
+
continue
|
|
1617
|
+
if state == "orphan":
|
|
1618
|
+
print(f"[warn] {rel}: git ref '{ref}' is not an ancestor of HEAD (amended, "
|
|
1619
|
+
"rebased, squash-merged, or marked on another branch): it stops "
|
|
1620
|
+
"resolving once git prunes it, and on any fresh clone. Re-mark now: "
|
|
1621
|
+
f"{entry} mark {rel}")
|
|
1565
1622
|
res = git_changed_since(root, ref, rel.replace("\\", "/"))
|
|
1566
1623
|
if res is None:
|
|
1567
|
-
print(f"[
|
|
1624
|
+
print(f"[stale] {rel}: git could not compare against ref '{ref}': its "
|
|
1625
|
+
"freshness cannot be evaluated. To fix, " + remark)
|
|
1626
|
+
unverifiable.append(rel)
|
|
1568
1627
|
continue
|
|
1569
1628
|
changed = res
|
|
1570
1629
|
else:
|
|
1571
1630
|
ts = parse_iso(ref)
|
|
1572
1631
|
if ts is None:
|
|
1573
|
-
print(f"[
|
|
1632
|
+
print(f"[stale] {rel}: reference '{ref}' is neither a git commit nor an ISO "
|
|
1633
|
+
"UTC timestamp: its freshness cannot be evaluated. To fix, " + remark)
|
|
1634
|
+
unverifiable.append(rel)
|
|
1574
1635
|
continue
|
|
1575
1636
|
for fp in iter_files(target):
|
|
1576
1637
|
mtime = datetime.fromtimestamp(fp.stat().st_mtime, tz=timezone.utc)
|
|
@@ -1583,8 +1644,11 @@ def cmd_stale(root, hybrid=False):
|
|
|
1583
1644
|
if changed:
|
|
1584
1645
|
stale.append((rel, changed))
|
|
1585
1646
|
|
|
1647
|
+
if unverifiable:
|
|
1648
|
+
rc = 1 # unverified is not fresh (F-056)
|
|
1586
1649
|
if not stale:
|
|
1587
|
-
|
|
1650
|
+
if not unverifiable:
|
|
1651
|
+
print("[ok] no analyzed area was modified after its last recorded analysis.")
|
|
1588
1652
|
return rc # was: return 0 — MUST carry guide rc
|
|
1589
1653
|
print("Areas modified after the last recorded analysis:")
|
|
1590
1654
|
for rel, changed in stale:
|
|
@@ -1593,7 +1657,7 @@ def cmd_stale(root, hybrid=False):
|
|
|
1593
1657
|
print(f" - {c}")
|
|
1594
1658
|
if len(changed) > 10:
|
|
1595
1659
|
print(f" ... and {len(changed) - 10} more")
|
|
1596
|
-
print("\nAfter re-analyzing, record it with:
|
|
1660
|
+
print(f"\nAfter re-analyzing, record it with: {entry} mark <path>")
|
|
1597
1661
|
return 1 # stale areas dominate: rc already implied
|
|
1598
1662
|
|
|
1599
1663
|
|
|
@@ -1645,6 +1709,13 @@ def cmd_mark(root, paths):
|
|
|
1645
1709
|
|
|
1646
1710
|
f.parent.mkdir(parents=True, exist_ok=True)
|
|
1647
1711
|
f.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
1712
|
+
if use_git_ref:
|
|
1713
|
+
# F-056: the reference is born here, so this is where the gestures that
|
|
1714
|
+
# orphan it are named. An amend was the observed one.
|
|
1715
|
+
print(f"[info] {ref} is the current HEAD. Commit this audit plan change as a new "
|
|
1716
|
+
"commit: amending, rebasing or squash-merging that commit orphans the "
|
|
1717
|
+
f"reference, and `{entry_script()} stale` fails once it no longer resolves. "
|
|
1718
|
+
"After a squash or rebase merge, re-mark on the integration branch.")
|
|
1648
1719
|
return 0
|
|
1649
1720
|
|
|
1650
1721
|
|