feat(cli): support fleet-node enrollment in `fleet serve`
Merged
KH
4mo ago+913+913+012345678901234567890123456789-47-47-01234567890123456789
What
Cloud's Enroll node UI mints:
agent-relay fleet serve --enrollment-token '<ocl_node_enr_...>' \
--enrollment-url 'https://agentrelay.com/api/v1/fleet/register' --name '<node>'
…but agent-relay fleet serve only accepted a <file> node-def plus --name/--workspace/--max-agents/--base-url, so the minted command errored on the unknown options. The Cloud endpoints (enrollment-tokens mint + register redeem + /fleet/nodes) already exist — this adds the missing CLI consumer.
Changes
fleet servegains--enrollment-tokenand--enrollment-url. When a token is provided, the CLI exchanges the one-time token at the enrollment URL (cloudPOST /api/v1/fleet/register) for durable node credentials before the broker boots.- New
enrollFleetNodein@agent-relay/cloud(packages/cloud/src/fleet.ts), modeled on the worker enrollment exchange (registerCloudWorker/cloud worker register --token): a single POST that redeems the token and returns{ nodeId, nodeName, nodeToken, relayWorkspaceId, relaycastUrl, websocketUrl }. Clear, actionable errors on expired/invalid/consumed tokens (401), rate-limit (429), and wrong-URL HTML 404s. - Credential wiring: the exchange sets
RELAY_NODE_TOKEN(the relaycast node token used over the fleet WS) andRELAY_BASE_URL(the relaycast origin), which is what the broker reads to bind itself to the Cloud workspace's fleet roster. <file>is now optional in enrollment mode. Identity/name/max-agents come from the enrollment record (falling back to an implicit local node viacreateImplicitLocalFleetNode); a<file>, when present, overrides/augments. Outside enrollment mode a<file>is still required.
Register endpoint contract (matched)
Request: { enrollmentToken, name?, capabilities?, maxAgents?, tags?, version? }
Response: { nodeId, nodeName, nodeToken, relayWorkspaceId, relaycastUrl, websocketUrl }
Tests
packages/cloud/src/fleet.test.ts— token exchange (trim/dedupe inputs), websocket-url derivation, 401/429/missing-creds/empty-token, and HTML-404 no-markup-dump (mocked fetch).packages/cli/src/cli/commands/fleet.test.ts— flag parsing + exchange wiring (env set), optional-<file>serving, and the two validation errors.- Full
packages/cloud+packages/clisuites green (508 passed, 5 skipped); lint clean; tsc clean.
Verify
node packages/cli/dist/cli/index.js fleet serve --help # lists both flags; [file] optional
🤖 Generated with Claude Code