Skip to content

Commit 06c8a9f

Browse files
khaliqgantProactive Runtime Botclaudeagent-relay-code[bot]github-actions[bot]
authored
feat(cli): drive relayfile integration ops over the control-plane socket (no shell-out) (#1215)
* feat(cli): drive relayfile integration ops over the control-plane socket (no shell-out) Replace the stringly-typed `spawn('relayfile', …)` + parse-stdout bridge with a typed client over relayfile's control-plane unix socket (`relayfile control-plane serve`). The contract is now version-negotiated via `/v1/hello`, and request/response types are generated from relayfile's OpenAPI — so field drift is a compile error, not a runtime surprise. - New `relayfile-client.ts`: HTTP/JSON over `http.request({ socketPath })`, `X-Relayfile-API-Version` handshake, daemon auto-start (+ RELAYFILE_REQUIRE_DAEMON strict mode), typed methods aliasing the generated schemas. - `defaultRelayfileBridge` swapped onto the client; `runRelayfile`/`spawn` deleted. The `RelayfileBridge` interface is unchanged, so subscribe/unsubscribe callers are untouched. - subscribe/unsubscribe now canonicalize the native `--resource` to relayfile's stored path-glob via `resolve-path` before keying find/unbind (fixes the silent native-vs-glob mismatch). - Types generated from a vendored copy of relayfile's openapi/relayfile-control-plane-v1.openapi.yaml (`npm run codegen:relayfile`). This is the interim home; it will be swapped to the published `@relayfile/client` package before merge once relayfile 0.10.16 ships. - Tests: real-daemon contract test (boots the daemon, drives the bridge over the socket) + client lifecycle units. Requires relayfile >= 0.10.16. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: apply pr-reviewer fixes for #1215 * fix(cli): harden the relayfile control-plane client (PR review) Addresses bot review on #1215: - spawn(): listen for the child's async 'error' event so a missing binary / bad RELAYFILE_BIN maps to DAEMON_UNAVAILABLE instead of crashing the CLI. - rawRequest(): add a per-request timeout so a hung socket rejects with DAEMON_UNAVAILABLE instead of blocking startDaemonAndConnect forever. - listen for 'error' on the response stream. - compareSemver(): default partial-semver components to 0 (avoid NaN). - assertRelayfileVersion(): throw a typed RelayfileControlPlaneError ('VERSION_INCOMPATIBLE') so callers re-throwing daemon/version failures by code don't silently swallow it. - resolveWritebackBinding(): re-throw DAEMON_UNAVAILABLE / VERSION_INCOMPATIBLE rather than masking a daemon outage as a missing secret. - test: auto-start with a missing binary fails fast with DAEMON_UNAVAILABLE. - CHANGELOG: [Unreleased] entry for the control-plane socket migration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(cli): bump MIN_RELAYFILE_VERSION to 0.10.17 relayfile already released 0.10.16 for the native-resource bind fix, so the control-plane + @relayfile/client release target moves to 0.10.17. Align the relay compat gate and version-gate tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: auto-format with Prettier * chore(cli): re-vendor relayfile control-plane OpenAPI from #344 Picks up the /v1/hello X-Relayfile-API-Version header docs added on the relayfile side, regenerates the client types, and prettier-ignores the vendored spec so it stays byte-identical to the authoritative source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(cli): consume published @relayfile/client; drop vendored interim @relayfile/client@0.10.17 is published, so swap the integration bridge onto the published package and delete the in-repo interim client + vendored OpenAPI + local codegen (openapi-typescript devDep, codegen:relayfile script). The client's lifecycle/version tests now live in the package; relay keeps the bridge-level real-daemon contract test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(cli): bump @relayfile/client to ^0.10.19 Pick up the latest published @relayfile/client. API version (1) and the daemon min (0.10.17) are unchanged, so the wire contract and version gate are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Proactive Runtime Bot <agent@agent-relay.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: agent-relay-code[bot] <agent-relay-code[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent b1a05af commit 06c8a9f

8 files changed

Lines changed: 335 additions & 122 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Changed
1515

16+
- `agent-relay integration` commands now talk to relayfile over its local **control-plane unix socket** (`relayfile control-plane serve`) via the published **`@relayfile/client`** package — a typed, version-negotiated client (`/v1/hello` handshake) — instead of shelling out to the `relayfile` CLI and parsing stdout. The daemon is auto-started on first use (or required already-running via `RELAYFILE_REQUIRE_DAEMON=1`); request/response types are generated from relayfile's OpenAPI so contract drift is a build error rather than a runtime surprise. The provider resource is canonicalized to relayfile's stored path-glob before bind/unbind so re-subscribing and unsubscribing match reliably. Requires relayfile ≥ 0.10.17.
1617
- `agent-relay integration subscribe` now points the writeback subscription at the relayfile-cloud ingress and signs it with a per-channel secret fetched from relayfile (`relayfile integration writeback-secret`), instead of a relay-server path that returned 404. The secret is derived server-side and tied to the logged-in account, so there's nothing to provision; `--bridge-url`/`--bridge-secret` still override.
1718
- relaycast SDKs upgraded to latest: `@relaycast/sdk` 5.0.5 (v4→v5 major), `relaycast` crate 5.0.2, `relaycast-sdk` 0.3.0, Swift relaycast 5.0.5. The v5 `agents.release` now returns an action invocation (like `agents.spawn`); the `remove_agent` MCP tool surfaces that invocation.
1819
- The hosted engine base URL default is owned solely by the relaycast SDK. `agent-relay`, `agent-relay-broker`, and the bundled SDKs no longer hardcode a base URL — they pass `RELAYCAST_BASE_URL`/`RELAY_BASE_URL` through for self-hosting and otherwise inherit the SDK default (`cast.agentrelay.com`). The broker reaches the fleet node-control endpoint via the SDK's `node_control_ws_url` helper and only injects `RELAY_BASE_URL` into spawned agents when an override is set.

package-lock.json

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cli/.eslintrc.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@ module.exports = {
4242
complexity: ['warn', 15],
4343
'max-depth': ['warn', 4],
4444
},
45-
ignorePatterns: ['dist/**', 'node_modules/**', 'coverage/**', '**/out/**'],
45+
ignorePatterns: ['dist/**', 'node_modules/**', 'coverage/**', '**/out/**', '**/*.gen.ts'],
4646
};

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@agent-relay/utils": "9.1.7",
5252
"@modelcontextprotocol/sdk": "^1.0.0",
5353
"@relaycast/sdk": "^5.0.5",
54+
"@relayfile/client": "^0.10.19",
5455
"@relayflows/cli": "^1.0.1",
5556
"@xterm/headless": "^6.0.0",
5657
"commander": "^12.1.0",

0 commit comments

Comments
 (0)