vault-cli: Librarian tooling for the R/J/F/I vault
Adds packages/vault-cli (the `vault` CLI: search/show/tree, clobber-safe create/move/rename across both /vault and /data + manifest regen, sync-data, report, analyze) and wires it onto $PATH via modules/hosts/core/vault.nix for server + vault-client hosts. Scripts self-locate siblings via realpath so they run from the Nix store. Includes the deterministic $0 report generator, the topology-manifest generator, and the shared Librarian prompt.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate/refresh the vault topology manifest note (source of truth for both trees)."""
|
||||
import os, json, sys, datetime
|
||||
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
||||
import vault_lib as vl
|
||||
|
||||
def render(manifest):
|
||||
ts = datetime.date.today().isoformat()
|
||||
c = manifest["counts"]
|
||||
lines = []
|
||||
lines.append("---")
|
||||
lines.append("tags: [meta, topology, jdex]")
|
||||
lines.append("generated: " + ts)
|
||||
lines.append("---")
|
||||
lines.append("# 00.05 Vault topology (machine-readable)")
|
||||
lines.append("")
|
||||
lines.append("> [!info] Source of truth")
|
||||
lines.append("> This note is the **authoritative topology** for the R/J/F/I vault. It is")
|
||||
lines.append("> regenerated from the live `/vault` structure by `vault-topology.py` and is")
|
||||
lines.append("> what the `vault` CLI and the nightly Librarian reconcile **both** `/vault`")
|
||||
lines.append("> (the JDex/map) and `/data` (blob territory) against. Do not hand-edit the")
|
||||
lines.append("> JSON block below — change the vault via the `vault` CLI and regenerate.")
|
||||
lines.append("")
|
||||
lines.append(f"**Live counts:** {c['systems']} systems · {c['areas']} areas · "
|
||||
f"{c['categories']} categories · {c['ids']} IDs")
|
||||
lines.append("")
|
||||
lines.append("## Systems")
|
||||
for k, v in manifest["systems"].items():
|
||||
lines.append(f"- **{k}** — {v}")
|
||||
lines.append("")
|
||||
lines.append("## Categories by system")
|
||||
# group categories under systems
|
||||
by_sys = {}
|
||||
for code, name in manifest["categories"].items():
|
||||
by_sys.setdefault(code[0], []).append((code, name))
|
||||
for s in sorted(by_sys):
|
||||
lines.append(f"### {s}")
|
||||
for code, name in sorted(by_sys[s]):
|
||||
n_ids = sum(1 for idc in manifest["ids"] if idc.startswith(code + "."))
|
||||
lines.append(f"- `{code}` {name.split(' ',1)[1] if ' ' in name else name} — {n_ids} IDs")
|
||||
lines.append("")
|
||||
lines.append("## Machine-readable topology")
|
||||
lines.append("")
|
||||
lines.append(vl.MANIFEST_BEGIN)
|
||||
lines.append("```json")
|
||||
lines.append(json.dumps(manifest, indent=2, ensure_ascii=False))
|
||||
lines.append("```")
|
||||
lines.append(vl.MANIFEST_END)
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
def main():
|
||||
manifest = vl.build_manifest()
|
||||
content = render(manifest)
|
||||
dest = os.path.join(vl.VAULT, vl.MANIFEST_REL)
|
||||
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
||||
dry = "--execute" not in sys.argv
|
||||
if dry:
|
||||
print("DRY-RUN. Would write manifest to:")
|
||||
print(" " + dest)
|
||||
print(f" ({manifest['counts']})")
|
||||
print("--- preview (first 40 lines) ---")
|
||||
print("\n".join(content.splitlines()[:40]))
|
||||
else:
|
||||
with open(dest, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
print("WROTE " + dest)
|
||||
print(f" {manifest['counts']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user