mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
A bond lives on the consumer's side of a service relation, so seeing how two roles couple means opening both roles' meta/services.yml and comparing, and retuning one means editing a scalar buried among dozens of unrelated keys. Add `infinito meta roles applications bond` (make bond / i8bond): it resolves every services.<key>.bond to a role-to-role edge through the service registry and serves the result as a matrix, each cell carrying both directions because the two need not agree. Brightness is the bond, black for none and white for 1, so the coupling of the whole repository reads at a glance. Clicking a cell writes the new value back to the declaring role. The write is line surgery rather than a YAML round-trip: these files carry `# nocheck:` directives and hand-tuned ordering that re-dumping would flatten, so only the bond scalar moves and a trailing comment on that line survives. The browser sends a role pair, never a path, and the server resolves the service key from its own edge map, so a pair it does not know is refused before any write. `--out FILE` exports a read-only page and `--format json` the raw edges, for callers that want to post-process rather than edit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
98 lines
2.7 KiB
Python
98 lines
2.7 KiB
Python
"""Serve the editable bond matrix, or export it as a static file."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import contextlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from utils import PROJECT_ROOT
|
|
|
|
from .matrix import collect_edges, participants
|
|
from .render import render, render_json
|
|
from .serve import serve
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(
|
|
prog="bond",
|
|
description=(
|
|
"Show which roles bond to which, and how tightly. Serves an editable "
|
|
"matrix on localhost; a cell edit rewrites the bond in the role."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--roles-dir",
|
|
default=str(PROJECT_ROOT / "roles"),
|
|
help="roles directory to read and write (default: the project's own)",
|
|
)
|
|
parser.add_argument(
|
|
"-o",
|
|
"--out",
|
|
default="",
|
|
help="export a read-only file here instead of serving",
|
|
)
|
|
parser.add_argument(
|
|
"--format",
|
|
choices=("html", "json"),
|
|
default="html",
|
|
help="export format, json implies --out (default: html)",
|
|
)
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=0,
|
|
help="port to serve on (default: any free port)",
|
|
)
|
|
parser.add_argument(
|
|
"--no-open",
|
|
action="store_true",
|
|
help="do not open a browser",
|
|
)
|
|
return parser
|
|
|
|
|
|
def _open(target: str) -> None:
|
|
"""Open the matrix with the desktop's handler, if there is one."""
|
|
opener = shutil.which("xdg-open") or shutil.which("open")
|
|
if not opener:
|
|
print(f"no xdg-open/open on PATH; the matrix is at {target}", file=sys.stderr)
|
|
return
|
|
subprocess.run([opener, target], check=False)
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
args = build_parser().parse_args(argv)
|
|
roles_dir = Path(args.roles_dir)
|
|
if not roles_dir.is_dir():
|
|
print(f"no such roles directory: {roles_dir}", file=sys.stderr)
|
|
return 2
|
|
|
|
edges = collect_edges(roles_dir)
|
|
if not edges:
|
|
print(f"no services.<key>.bond found under {roles_dir}", file=sys.stderr)
|
|
return 1
|
|
|
|
if args.format == "json":
|
|
payload = render_json(edges)
|
|
if not args.out:
|
|
print(payload)
|
|
return 0
|
|
elif args.out:
|
|
payload = render(edges, participants(edges))
|
|
else:
|
|
httpd, url = serve(roles_dir, edges, args.port)
|
|
print(f"{url} ({len(edges)} bonds, editing writes to {roles_dir})")
|
|
if not args.no_open:
|
|
_open(url)
|
|
with contextlib.suppress(KeyboardInterrupt), httpd:
|
|
httpd.serve_forever()
|
|
return 0
|
|
|
|
Path(args.out).write_text(payload, encoding="utf-8")
|
|
print(args.out)
|
|
return 0
|