From 4e78e52144a0660e0b5e7b67fec0251604914cbd Mon Sep 17 00:00:00 2001 From: Will Washburn Date: Thu, 4 Jun 2026 09:18:41 -0400 Subject: [PATCH 1/2] ci(publish): publish @agent-relay/harnesses on release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @agent-relay/harnesses was set up as a public package (no private flag, publishConfig.access public, versioned in lockstep) but was never wired into the publish workflow, so it never reached npm. External SDK consumers (e.g. relayflows) need it for the prebuilt PTY harnesses and the definePtyHarness/createHuman author helpers. Add a publish-harnesses job to the package=all path. It runs after publish-packages — where its exact-version workspace deps (@agent-relay/sdk, @agent-relay/harness-driver) land on the registry — so an external `npm install @agent-relay/harnesses@` can always resolve its dependencies. Mirrors the existing provenance + skip-if-exists publish pattern. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish.yml | 49 +++++++++++++++++++++++++++++++++++ CHANGELOG.md | 1 + 2 files changed, 50 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c5698cd5a..596284f75 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -964,6 +964,55 @@ jobs: fi npm publish --access public --provenance --tag ${{ github.event.inputs.tag }} --ignore-scripts + # Publish @agent-relay/harnesses after the publish-packages matrix, which is + # where its exact-version workspace deps (@agent-relay/sdk and + # @agent-relay/harness-driver) land on the registry. Publishing harnesses + # before those exist would leave a window where + # `npm install @agent-relay/harnesses@` cannot resolve its dependencies — + # the same install race the broker/sdk ordering above is built to avoid. + publish-harnesses: + name: Publish @agent-relay/harnesses + needs: [build, publish-packages] + runs-on: ubuntu-latest + if: github.event.inputs.package == 'all' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.14.0' + registry-url: 'https://registry.npmjs.org' + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-output + path: . + + - name: Update npm for OIDC support + run: npm install -g npm@latest + + - name: Dry run check + if: github.event.inputs.dry_run == 'true' + working-directory: packages/harnesses + run: npm publish --dry-run --access public --tag ${{ github.event.inputs.tag }} --ignore-scripts + + - name: Publish to NPM + if: github.event.inputs.dry_run != 'true' + working-directory: packages/harnesses + run: | + set -euo pipefail + PKG_NAME=$(node -p "require('./package.json').name") + PKG_VERSION=$(node -p "require('./package.json').version") + if npm view "${PKG_NAME}@${PKG_VERSION}" version >/dev/null 2>&1; then + echo "${PKG_NAME}@${PKG_VERSION} already exists on npm; skipping publish" + exit 0 + fi + npm publish --access public --provenance --tag ${{ github.event.inputs.tag }} --ignore-scripts + # package=main publishes only the root `agent-relay` tarball, but that # tarball pins several @agent-relay/* runtime dependencies to the freshly # bumped version. Publish those direct deps first so a main-only release diff --git a/CHANGELOG.md b/CHANGELOG.md index ec20c9775..277c10305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `@agent-relay/harnesses` is now published to npm, so external SDK consumers can install the prebuilt PTY harnesses (`claude`, `codex`, `gemini`, …) and the `definePtyHarness`/`defineHarness`/`createHuman` author helpers. - `agent-relay drive` and `agent-relay passthrough` add adaptive predictive echo so typing stays responsive when driving a high-latency or remote agent, and stays invisible on fast local links. - `@agent-relay/harness-driver` exports a reusable `PredictiveEchoEngine` so other attach UIs (CLI, Electron, browser) can share one predictive-echo implementation. - `@agent-relay/sdk` `relay.addListener(...)` on a workspace client now receives all workspace-visible events: `events.connect()` opens the relaycast 2.5 workspace stream when no agent client is present, so the documented `relay.addListener('message.created', ...)` quickstart path streams without registering an agent. From 4da8efc7bcfc684e3e3cbc87cb427dbdc0e5d09b Mon Sep 17 00:00:00 2001 From: Will Washburn Date: Thu, 4 Jun 2026 09:36:44 -0400 Subject: [PATCH 2/2] ci(publish): gate release on publish-harnesses; trim changelog Address PR review: publish-harnesses ran outside the release gate, so a tag/release could be cut even if harness publishing failed. - create-release now needs publish-harnesses and its `if` requires the job to not have failed. It tolerates `skipped` so package=main releases (where publish-harnesses does not run) are not blocked. - summary job lists the harness publish result. - Trim the changelog bullet to impact-first per the repo changelog rule. Leaving the new job's actions on @v4 tags to match the rest of the workflow (the repo uses tag refs throughout; SHA-pinning would be inconsistent and is not the enforced policy here). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish.yml | 9 ++++++++- CHANGELOG.md | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 596284f75..e33d4cd34 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1577,13 +1577,18 @@ jobs: # Create git tag and release create-release: name: Create Release - needs: [build, build-broker, build-standalone, verify-binaries, publish-main] + needs: [build, build-broker, build-standalone, verify-binaries, publish-main, publish-harnesses] runs-on: ubuntu-latest + # publish-harnesses only runs for package=all; for a package=main release it + # is skipped, which must not block the tag. Gate on "not failed" rather than + # "succeeded" so a real harness publish failure stops the release but a + # skipped one does not. if: | always() && github.event.inputs.package != 'cli-prerelease' && github.event.inputs.dry_run != 'true' && needs.publish-main.result == 'success' && + (needs.publish-harnesses.result == 'success' || needs.publish-harnesses.result == 'skipped') && needs.publish-main.outputs.published == 'true' steps: @@ -2060,6 +2065,7 @@ jobs: publish-sdk-internal-deps, publish-broker-packages, publish-packages, + publish-harnesses, publish-brand-only, publish-sdk-py, publish-main, @@ -2102,6 +2108,7 @@ jobs: echo "| Publish SDK Internal Deps | ${{ needs.publish-sdk-internal-deps.result == 'success' && '✅' || (needs.publish-sdk-internal-deps.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-sdk-internal-deps.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Publish Broker Packages | ${{ needs.publish-broker-packages.result == 'success' && '✅' || (needs.publish-broker-packages.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-broker-packages.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Publish Packages | ${{ needs.publish-packages.result == 'success' && '✅' || (needs.publish-packages.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-packages.result }} |" >> $GITHUB_STEP_SUMMARY + echo "| Publish Harnesses | ${{ needs.publish-harnesses.result == 'success' && '✅' || (needs.publish-harnesses.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-harnesses.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Publish Brand | ${{ needs.publish-brand-only.result == 'success' && '✅' || (needs.publish-brand-only.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-brand-only.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Publish Python SDK | ${{ needs.publish-sdk-py.result == 'success' && '✅' || (needs.publish-sdk-py.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-sdk-py.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Publish Main | ${{ needs.publish-main.result == 'success' && '✅' || (needs.publish-main.result == 'skipped' && '⏭️' || '❌') }} ${{ needs.publish-main.result }} |" >> $GITHUB_STEP_SUMMARY diff --git a/CHANGELOG.md b/CHANGELOG.md index 277c10305..f26466668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `@agent-relay/harnesses` is now published to npm, so external SDK consumers can install the prebuilt PTY harnesses (`claude`, `codex`, `gemini`, …) and the `definePtyHarness`/`defineHarness`/`createHuman` author helpers. +- `@agent-relay/harnesses` is now published to npm, so SDK consumers can install the prebuilt PTY harnesses and harness-authoring helpers. - `agent-relay drive` and `agent-relay passthrough` add adaptive predictive echo so typing stays responsive when driving a high-latency or remote agent, and stays invisible on fast local links. - `@agent-relay/harness-driver` exports a reusable `PredictiveEchoEngine` so other attach UIs (CLI, Electron, browser) can share one predictive-echo implementation. - `@agent-relay/sdk` `relay.addListener(...)` on a workspace client now receives all workspace-visible events: `events.connect()` opens the relaycast 2.5 workspace stream when no agent client is present, so the documented `relay.addListener('message.created', ...)` quickstart path streams without registering an agent.