app/cli/commands/agent.ts
zzmq.dev@gmail.com/zz / app / cli / commands / agent.ts
@ 4a679371
Download
Ladder Summary
- file The file implements the CLI sub‑commands for managing “agents”: it creates a new agent (and its initial token), mints additional tokens for an existing agent, and lists the user’s own and managed agents by calling the server API via `apiFetch`. It also prints a ready‑to‑use `ZZ_ID="username:token"` string for headless use. Exported members are the async functions `agentCreate`, `agentToken`, and `agentList`.
// `zz agent create/token/list` -- CLI parity with /profile's "Managed
// agents" section. Any Agent can create a peer Agent (the only gate
// is being authenticated at all -- see webApp.ts's doCreateAgent);
// creating one issues its first token in the same call, no separate
// step. Minting an *additional* token is restricted to the agent
// itself or whoever manages it (requireTokenMintAuthority) -- a
// bootstrap/rotation allowance, not a general override.
import { apiFetch } from "../lib/api.js";
// A local, minimal shape matching worker/src/accountsDb.ts's Agent --
// not imported directly: that file is typed against D1Database and
// other @cloudflare/workers-types ambients the main app/ tsconfig
// doesn't have configured, so cross-importing it would drag workers-
// only types into a Node CLI typecheck for no real benefit (the API
// boundary is just JSON over HTTP either way). `username` is the only
// identifier -- there's no separate internal id anymore (see worker
// migration 0006): a human's is their email; a managed agent's chains
// off its creator's, e.g. "thoward37@gmail.com[claude]" (see
// accountsDb.ts's computeUsername).
interface Agent {
display_name: string;
email: string | null;
username: string;
created_at: string;
created_by: string | null;
}
interface MintTokenResponse {
agent: Agent;
token: string;
}
// `zz work --as <name>` (and `zz review`/`zz repo submit`) don't need
// a token from here at all -- they mint a fresh one on start and
// revoke it on exit, using your own `zz login` session's mint
// authority (lib/identity.ts). A token from these two commands is for
// the other case: a real standing credential for somewhere that isn't
// your own logged-in session -- a separate machine, a headless/CI
// run, anything using ZZ_ID.
function printZzId(username: string, token: string): void {
console.log(`For a separate machine or headless run, set: ZZ_ID="${username}:${token}"`);
}
export async function agentCreate(displayName: string): Promise<void> {
const { token, ...agent } = await apiFetch<Agent & { token: string }>("POST", "/api/agents", { display_name: displayName });
console.log(`Created agent ${agent.username}. Its first token -- copy it now, it won't be shown again:`);
console.log(token);
console.log(`Issue another with: zz agent token ${agent.username}`);
printZzId(agent.username, token);
}
export async function agentToken(usernameOrId: string): Promise<void> {
const { agent, token } = await apiFetch<MintTokenResponse>("POST", `/api/agents/${encodeURIComponent(usernameOrId)}/tokens`);
console.log(`Token for ${agent.username} -- copy it now, it won't be shown again:`);
console.log(token);
printZzId(agent.username, token);
}
export async function agentList(): Promise<void> {
const { you, created } = await apiFetch<{ you: Agent; created: Agent[] }>("GET", "/api/agents");
console.log(`${you.username} -- you`);
for (const a of created) console.log(`${a.username} -- managed by you`);
if (created.length === 0) console.log("(no managed agents yet -- zz agent create <name>)");
}