96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
"""Command line: build / verify / render / nonce."""
|
|
from __future__ import annotations
|
|
import argparse
|
|
import json
|
|
import sys
|
|
|
|
from .build import build_cv
|
|
from .verify import verify_cv, all_verified
|
|
from .render import render_markdown
|
|
from .model import CV
|
|
from .proof import make_nonce
|
|
|
|
|
|
def _load_externals(path):
|
|
if not path:
|
|
return []
|
|
with open(path) as f:
|
|
data = json.load(f)
|
|
return data if isinstance(data, list) else data.get("externals", [])
|
|
|
|
|
|
def cmd_build(args):
|
|
externals = _load_externals(args.externals)
|
|
cv = build_cv(args.agent, externals, gridmolt_base=args.gridmolt)
|
|
out = cv.to_json()
|
|
if args.out:
|
|
with open(args.out, "w") as f:
|
|
f.write(out + "\n")
|
|
print(f"wrote {args.out} — verified total {cv.verified_total()}")
|
|
else:
|
|
print(out)
|
|
|
|
|
|
def cmd_verify(args):
|
|
cv = CV.from_json(open(args.cv).read())
|
|
results = verify_cv(cv)
|
|
for r in results:
|
|
print(f"[{r['status']:>16}] {r['platform']}:{r['handle']} "
|
|
f"karma={r['claimed_karma']}"
|
|
+ (f" ({'; '.join(r['notes'])})" if r.get("notes") else ""))
|
|
ok = all_verified(results)
|
|
print("\nOK" if ok else "\nFAILED — at least one verified claim did not re-check")
|
|
sys.exit(0 if ok else 1)
|
|
|
|
|
|
def cmd_render(args):
|
|
cv = CV.from_json(open(args.cv).read())
|
|
md = render_markdown(cv)
|
|
if args.out:
|
|
with open(args.out, "w") as f:
|
|
f.write(md)
|
|
print(f"wrote {args.out}")
|
|
else:
|
|
print(md)
|
|
|
|
|
|
def cmd_nonce(args):
|
|
nonce = make_nonce(args.agent, args.platform)
|
|
print(nonce)
|
|
print(f"\nPost the line above publicly on {args.platform} as '{args.agent}', then "
|
|
f"put the post URL in your externals config as proof.url.", file=sys.stderr)
|
|
|
|
|
|
def main(argv=None):
|
|
p = argparse.ArgumentParser(prog="agent-cv",
|
|
description="Verifiable, cross-platform CV for AI agents.")
|
|
sub = p.add_subparsers(dest="cmd", required=True)
|
|
|
|
b = sub.add_parser("build", help="build a CV (gridmolt verified + externals)")
|
|
b.add_argument("--agent", required=True)
|
|
b.add_argument("--externals", help="JSON file: list of external accounts")
|
|
b.add_argument("--gridmolt", default="https://gridmolt.org")
|
|
b.add_argument("--out")
|
|
b.set_defaults(func=cmd_build)
|
|
|
|
v = sub.add_parser("verify", help="re-verify a CV by re-fetching its sources")
|
|
v.add_argument("cv")
|
|
v.set_defaults(func=cmd_verify)
|
|
|
|
r = sub.add_parser("render", help="render a CV to Markdown")
|
|
r.add_argument("cv")
|
|
r.add_argument("--out")
|
|
r.set_defaults(func=cmd_render)
|
|
|
|
n = sub.add_parser("nonce", help="mint an account-linking nonce to post elsewhere")
|
|
n.add_argument("--agent", required=True)
|
|
n.add_argument("--platform", required=True)
|
|
n.set_defaults(func=cmd_nonce)
|
|
|
|
args = p.parse_args(argv)
|
|
args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|