feat(sdk): expose the flows CLI as a mountable relay CLI surface
Part of a cross-repo change mounting every Relay product into the agent-relay
CLI. This repo's half: @relayflows/sdk gains a ./relay-cli export that
agent-relay mounts as agent-relay flows, without relay reimplementing a
single flows command.
What this does
@relayflows/sdk/relay-cliexportscreateRelayCliSurface()returning a
contract-v1 surface.rundelegates straight to therunClithis package
already ships, andcommandsis projected from the sameCLI_VERBStable
parseArgsdispatches on — so the declared tree and the dispatcher read from
one source rather than two that can rot apart. A drift test walks both.runClino longer touches process state. Output routes through the
injectedCliIo, and it returns an exit code rather than exiting.
packages/relayflows/bin/flows.jskeeps working unchanged on the same path.- Structurally typed against
@agent-relay/cli-surfacewithout importing
it, so the published package gains no runtime dependency on relay.
Why the declared tree matters
agent-relay renders help from this spec rather than forwarding --help to the
product — forwarding would print flows run ... when the user typed
agent-relay flows run. That makes commands user-visible output, not an
internal detail, so descriptions and flags are written to be read.
v1 → v2 mapping
relay is deprecating its v1 relayflows surface against this one. The scoping
that came out of it:
agent-relay cloud run --relayflow-version v1→agent-relay flows run --cloudagent-relay node workflow run|logs|sync(pinned to@relayflows/cli1.0.1)
→agent-relay flows run|replay|synccloud schedule/scheduleshave no v2 equivalent —tickis a local
cadence, not hosted scheduling — so relay keeps them supported and visible
rather than pointing at a command that cannot do the job.
Verification
tests/relay-cli-surface.test.ts— 29 tests.- Verified mounted:
agent-relay flows --helplists all 14 commands, and
agent-relay flows check <fixture>runs the real compiler toCHECK PASSED.
Release
Nothing is published. agent-relay pins the published version and currently
reports "upgrade @relayflows/sdk" until this ships.
🤖 Generated with Claude Code
[!NOTE]
Medium Risk
Changes cloud sync patch application (exclusions, multi-path, dry-run) and embeddable CLI cancellation; mistakes could skip or mis-apply agent output in local trees, though behavior is heavily tested.
Overview
Adds @relayflows/sdk/relay-cli so agent-relay can mount flows as agent-relay flows: createRelayCliSurface() projects CLI_VERBS into the host command tree and delegates run to runCli, with drift and contract tests so declared help and parsing stay aligned. runCli now accepts an optional AbortSignal (no global SIGINT/SIGTERM when embedded); the standalone flows binary behavior is unchanged.
flows sync is extended to match documented Cloud behavior: runtime paths (.agent-bin/**, trajectories, relayfile state, etc.) are skipped via git apply --exclude on both check and apply; --dry-run prints or JSON-embeds the patch; multi-path runs are inspectable in dry-run but applying stays sync_unsupported. Parser/help fixes include build --verify + --json, bundle deploy --json, and serve-webhook defaulting --data-dir.
Reviewed by Cursor Bugbot for commit d5f987ca7e209ceada5fd1203b1deb60ad75281e. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Exposes the flows CLI as a mountable relay CLI surface (agent-relay flows) and turns flows sync into a drop-in replacement for agent-relay cloud sync. The parsers now accept what the command surface advertises, so users following the host's help no longer hit exit 2.
New Features
createRelayCliSurface()returns a contract-v1 surface;rundelegates torunCli, andcommandsprojects from the sameCLI_VERBStable that gatesparseArgs.- Compile-time assertions force every
ParsedArgsvariant to be claimed by a declared verb, and vice versa. - The surface claims the
answer,schedule,schedules,unscheduleverbs and the--no-connectflag on the cloud-handoff verbs. runCliaccepts an optionalAbortSignal; with one supplied it installs no process signal handlers, while the standaloneflowsbinary keeps its SIGINT/SIGTERM behavior unchanged.- The surface is structurally typed against
@agent-relay/cli-surfacewithout importing it, so the published package gains no runtime dependency on relay. @agent-relay/cli-surfaceis a devDependency pinned to^12.2.4; the sibling-checkout alias was dropped so tests resolve the published package.
Bug Fixes
flows syncexcludes the agent runtime's own bookkeeping paths from applied patches, reports them as skipped, and uses identical exclusions on bothgit applyinvocations.flows sync --dry-runprints the patch and applies nothing; under--jsonthe diff travels in thepatchfield.- Multi-path runs are shown per path with
--dry-run; applying stays refused (sync_unsupported) since they target different repositories. serve-webhooknow defaults--data-dirlike the other verbs;build --verifyis an ordinary flag usable with--json(--outstays refused);deploy --jsonworks on the bundle form.run --cloudpasses the caller's signal through to the connect preflight, so submissions there no longer die with a ReferenceError and aborted submissions surface assubmission_aborted.- An empty multi-path patch now reports NO CHANGES instead of
patch_conflict.