@antoneeo/kb-agentic-skill 1.17.0 → 1.19.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 +44 -0
- package/README.md +176 -160
- package/gemini-extension.json +1 -1
- package/package.json +3 -1
- package/scripts/init.js +6 -17
- package/skills/kb-agentic-skill/ENFORCEMENT.md +3 -3
- package/skills/kb-agentic-skill/SKILL.md +303 -295
- package/skills/kb-agentic-skill/dispatch.md +5 -1
- package/skills/kb-agentic-skill/elicitation.md +192 -133
- package/skills/kb-agentic-skill/memory.md +88 -0
- package/skills/kb-agentic-skill/review.md +8 -1
- package/skills/kb-agentic-skill/routing.md +7 -1
- package/skills/kb-agentic-skill/scripts/knowledge.py +2089 -0
- package/skills/kb-agentic-skill/scripts/sdlc_check.py +62 -2044
- package/skills/kb-agentic-skill/scripts/sdlc_core.py +84 -5
- package/skills/kb-agentic-skill/templates.md +1 -1
|
@@ -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,18 @@ 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
|
+
# The audit plan records the marks: its own edits are not a change to the area
|
|
1578
|
+
# that contains it. Counting them made a committed hash mark of that area
|
|
1579
|
+
# stale again, and every re-mark repeated the loop.
|
|
1580
|
+
try:
|
|
1581
|
+
plan_rel = f.resolve().relative_to(Path(root).resolve()).as_posix()
|
|
1582
|
+
except ValueError:
|
|
1583
|
+
plan_rel = None
|
|
1584
|
+
# F-056: an ANALYZED row whose reference cannot be evaluated is UNVERIFIED,
|
|
1585
|
+
# never fresh. Each `continue` below that skips such a row records it here;
|
|
1586
|
+
# skipping silently is how a pruned reference printed `[ok]` over three areas.
|
|
1587
|
+
unverifiable = []
|
|
1546
1588
|
stale = []
|
|
1547
1589
|
for row in rows:
|
|
1548
1590
|
if row["status"] != "ANALYZED":
|
|
@@ -1561,16 +1603,42 @@ def cmd_stale(root, hybrid=False):
|
|
|
1561
1603
|
print(f"[warn] {rel}: path does not exist")
|
|
1562
1604
|
continue
|
|
1563
1605
|
changed = []
|
|
1564
|
-
|
|
1606
|
+
remark = f"re-analyze the area, then run: {entry} mark {rel}"
|
|
1607
|
+
if re.fullmatch(r"[0-9a-fA-F]{7,40}", ref or ""):
|
|
1608
|
+
if not use_git:
|
|
1609
|
+
print(f"[stale] {rel}: reference '{ref}' is a git commit, but git is not usable "
|
|
1610
|
+
"here (not a git work tree, git missing, or the repository refused): its "
|
|
1611
|
+
"freshness cannot be evaluated. Run stale inside the git work tree, or "
|
|
1612
|
+
+ remark)
|
|
1613
|
+
unverifiable.append(rel)
|
|
1614
|
+
continue
|
|
1615
|
+
state = git_ref_state(root, ref)
|
|
1616
|
+
if state == "missing":
|
|
1617
|
+
shallow = (" This clone is shallow: full history may hold it "
|
|
1618
|
+
"(git fetch --unshallow)." if git_is_shallow(root) else "")
|
|
1619
|
+
print(f"[stale] {rel}: git ref '{ref}' is not a commit in this repository "
|
|
1620
|
+
"(amended, rebased or squash-merged away and pruned, or never fetched "
|
|
1621
|
+
f"here): its freshness cannot be evaluated.{shallow} To fix, " + remark)
|
|
1622
|
+
unverifiable.append(rel)
|
|
1623
|
+
continue
|
|
1624
|
+
if state == "orphan":
|
|
1625
|
+
print(f"[warn] {rel}: git ref '{ref}' is not an ancestor of HEAD (amended, "
|
|
1626
|
+
"rebased, squash-merged, or marked on another branch): it stops "
|
|
1627
|
+
"resolving once git prunes it, and on any fresh clone. Re-mark now: "
|
|
1628
|
+
f"{entry} mark {rel}")
|
|
1565
1629
|
res = git_changed_since(root, ref, rel.replace("\\", "/"))
|
|
1566
1630
|
if res is None:
|
|
1567
|
-
print(f"[
|
|
1631
|
+
print(f"[stale] {rel}: git could not compare against ref '{ref}': its "
|
|
1632
|
+
"freshness cannot be evaluated. To fix, " + remark)
|
|
1633
|
+
unverifiable.append(rel)
|
|
1568
1634
|
continue
|
|
1569
1635
|
changed = res
|
|
1570
1636
|
else:
|
|
1571
1637
|
ts = parse_iso(ref)
|
|
1572
1638
|
if ts is None:
|
|
1573
|
-
print(f"[
|
|
1639
|
+
print(f"[stale] {rel}: reference '{ref}' is neither a git commit nor an ISO "
|
|
1640
|
+
"UTC timestamp: its freshness cannot be evaluated. To fix, " + remark)
|
|
1641
|
+
unverifiable.append(rel)
|
|
1574
1642
|
continue
|
|
1575
1643
|
for fp in iter_files(target):
|
|
1576
1644
|
mtime = datetime.fromtimestamp(fp.stat().st_mtime, tz=timezone.utc)
|
|
@@ -1580,11 +1648,15 @@ def cmd_stale(root, hybrid=False):
|
|
|
1580
1648
|
except ValueError: # symlink out of the tree: report absolute, never crash
|
|
1581
1649
|
name = str(fp)
|
|
1582
1650
|
changed.append(name)
|
|
1651
|
+
changed = [c for c in changed if c != plan_rel]
|
|
1583
1652
|
if changed:
|
|
1584
1653
|
stale.append((rel, changed))
|
|
1585
1654
|
|
|
1655
|
+
if unverifiable:
|
|
1656
|
+
rc = 1 # unverified is not fresh (F-056)
|
|
1586
1657
|
if not stale:
|
|
1587
|
-
|
|
1658
|
+
if not unverifiable:
|
|
1659
|
+
print("[ok] no analyzed area was modified after its last recorded analysis.")
|
|
1588
1660
|
return rc # was: return 0 — MUST carry guide rc
|
|
1589
1661
|
print("Areas modified after the last recorded analysis:")
|
|
1590
1662
|
for rel, changed in stale:
|
|
@@ -1593,7 +1665,7 @@ def cmd_stale(root, hybrid=False):
|
|
|
1593
1665
|
print(f" - {c}")
|
|
1594
1666
|
if len(changed) > 10:
|
|
1595
1667
|
print(f" ... and {len(changed) - 10} more")
|
|
1596
|
-
print("\nAfter re-analyzing, record it with:
|
|
1668
|
+
print(f"\nAfter re-analyzing, record it with: {entry} mark <path>")
|
|
1597
1669
|
return 1 # stale areas dominate: rc already implied
|
|
1598
1670
|
|
|
1599
1671
|
|
|
@@ -1645,6 +1717,13 @@ def cmd_mark(root, paths):
|
|
|
1645
1717
|
|
|
1646
1718
|
f.parent.mkdir(parents=True, exist_ok=True)
|
|
1647
1719
|
f.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
1720
|
+
if use_git_ref:
|
|
1721
|
+
# F-056: the reference is born here, so this is where the gestures that
|
|
1722
|
+
# orphan it are named. An amend was the observed one.
|
|
1723
|
+
print(f"[info] {ref} is the current HEAD. Commit this audit plan change as a new "
|
|
1724
|
+
"commit: amending, rebasing or squash-merging that commit orphans the "
|
|
1725
|
+
f"reference, and `{entry_script()} stale` fails once it no longer resolves. "
|
|
1726
|
+
"After a squash or rebase merge, re-mark on the integration branch.")
|
|
1648
1727
|
return 0
|
|
1649
1728
|
|
|
1650
1729
|
|
|
@@ -376,7 +376,7 @@ remains is derived — the next window is the next pending task.
|
|
|
376
376
|
|
|
377
377
|
## ai_docs/audit/audit_plan.md (Standalone mode only)
|
|
378
378
|
|
|
379
|
-
The `Reference` field (git hash or ISO UTC timestamp) is managed by `sdlc_check.py mark` — do not fill it by hand. Freshness is verified with `sdlc_check.py stale`.
|
|
379
|
+
The `Reference` field (git hash or ISO UTC timestamp) is managed by `sdlc_check.py mark` — do not fill it by hand. Freshness is verified with `sdlc_check.py stale`. Commit the `mark` result as a new commit: amending, rebasing or squash-merging the commit it recorded orphans the reference, and `stale` fails once it no longer resolves — after a squash or rebase merge, re-mark on the integration branch.
|
|
380
380
|
|
|
381
381
|
```markdown
|
|
382
382
|
# Audit Plan
|