| 1 | // mint-invite.mjs — mint one agent invite via the admin API and print its secret. |
| 2 | // |
| 3 | // Used by `lchat add-bot` to provision a sidecar identity. It reuses |
| 4 | // web/static/crypto.js so the id + claim_hash it derives from the secret T match |
| 5 | // exactly what the sidecar (provision.mjs) computes from the same T — the crypto |
| 6 | // never diverges (the whole reason the bot is Node). Reads LCHAT_BASE + |
| 7 | // LCHAT_ADMIN_TOKEN from the env; takes --label / --description / --model / |
| 8 | // --listen. Prints the bare secret T (the sidecar's LCHAT_*_INVITE) to stdout; |
| 9 | // all diagnostics go to stderr. |
| 10 | import { randomSecret, deriveInvite } from "../web/static/crypto.js"; |
| 11 | |
| 12 | const BASE = (process.env.LCHAT_BASE || "").replace(/\/$/, ""); |
| 13 | const ADMIN = (process.env.LCHAT_ADMIN_TOKEN || "").trim(); |
| 14 | if (!BASE || !ADMIN) { |
| 15 | console.error("mint-invite: set LCHAT_BASE and LCHAT_ADMIN_TOKEN"); |
| 16 | process.exit(1); |
| 17 | } |
| 18 | |
| 19 | function arg(name, def = "") { |
| 20 | const i = process.argv.indexOf(`--${name}`); |
| 21 | return i >= 0 && i + 1 < process.argv.length ? process.argv[i + 1] : def; |
| 22 | } |
| 23 | |
| 24 | const label = arg("label"); |
| 25 | if (!label) { |
| 26 | console.error("mint-invite: --label is required"); |
| 27 | process.exit(1); |
| 28 | } |
| 29 | |
| 30 | const T = randomSecret(); |
| 31 | const { id, claimHash } = await deriveInvite(T); |
| 32 | const res = await fetch(`${BASE}/api/admin/key-invites`, { |
| 33 | method: "POST", |
| 34 | headers: { "content-type": "application/json", authorization: `Bearer ${ADMIN}` }, |
| 35 | body: JSON.stringify({ |
| 36 | label, |
| 37 | id, |
| 38 | wrapped: "", |
| 39 | claim_hash: claimHash, |
| 40 | agent: true, |
| 41 | available_to_members: true, // in the Helpers catalog, so Eleven's roster baseline sees members |
| 42 | description: arg("description"), |
| 43 | model: arg("model"), |
| 44 | listen: arg("listen"), // "", "mention", or "name" |
| 45 | }), |
| 46 | }); |
| 47 | if (!res.ok) { |
| 48 | const detail = await res.text().catch(() => ""); |
| 49 | console.error(`mint-invite: POST /api/admin/key-invites -> HTTP ${res.status} ${detail}`); |
| 50 | process.exit(1); |
| 51 | } |
| 52 | process.stdout.write(T); // the bare secret; add-bot writes it as the sidecar's LCHAT_*_INVITE |
| 53 | |