Skip to content

feat(THU-601): connect local ACP/MCP agents via stdio-bridge from the… #2

feat(THU-601): connect local ACP/MCP agents via stdio-bridge from the…

feat(THU-601): connect local ACP/MCP agents via stdio-bridge from the… #2

# This Source Code Form is subject to the terms of the Mozilla Public

Check failure on line 1 in .github/workflows/stdio-bridge-release.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/stdio-bridge-release.yml

Invalid workflow file

(Line: 41, Col: 17): Unrecognized named-value: 'github'. Located at position 12 within expression: startsWith(github.ref, 'refs/tags/stdio-bridge-v') && 'write' || 'read', (Line: 41, Col: 17): Unexpected value '${{ startsWith(github.ref, 'refs/tags/stdio-bridge-v') && 'write' || 'read' }}'
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Build, smoke-test, and (on a tag) publish the thunderbolt-stdio-bridge CLI.
#
# On every push/PR touching thunderbolt-stdio-bridge/** we bundle bridge.cjs and
# prove all three entry points work: --help exits 0, the ACP face prints its
# `listening` banner, the MCP face prints its `mcp-listening` banner. On a
# `stdio-bridge-v*` tag we additionally attach bridge.cjs to the tag's GitHub
# Release, which install.sh fetches via releases/download/stdio-bridge-v<v>/.
name: stdio-bridge release
on:
push:
branches: [main]
paths: ['thunderbolt-stdio-bridge/**']
tags: ['stdio-bridge-v*']
pull_request:
paths: ['thunderbolt-stdio-bridge/**']
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
defaults:
run:
working-directory: thunderbolt-stdio-bridge
jobs:
build:
name: Build & smoke-test bridge.cjs
runs-on: ubuntu-24.04
# The tag job needs write to publish the release; everything else stays read.
permissions:
contents: ${{ startsWith(github.ref, 'refs/tags/stdio-bridge-v') && 'write' || 'read' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.14
- run: bun install --frozen-lockfile
- run: bun run build
# bridge.cjs parses and --help exits 0 (no child, no framing at risk).
- name: Smoke --help
run: |
node dist/bridge.cjs --help | grep -q "thunderbolt-stdio-bridge"
node dist/bridge.cjs --version
# ACP face: bind the WS face over a trivial `cat` child and confirm the
# readiness banner reaches stderr (token: `listening`). Capture stderr to a
# file, poll until the banner lands, then kill the still-running bridge.
- name: Smoke ACP (listening)
run: |
node dist/bridge.cjs --mode acp --json -- cat 2>acp.log &
pid=$!
for _ in $(seq 1 50); do
grep -q '"event":"listening"' acp.log && break
sleep 0.2
done
kill "$pid" 2>/dev/null || true
grep -q '"event":"listening"' acp.log
grep -q 'ws://127.0.0.1:' acp.log
# MCP face: bridge the bundled server-everything stdio server and confirm
# the readiness banner reaches stderr (token: `mcp-listening`).
- name: Smoke MCP (mcp-listening)
run: |
node dist/bridge.cjs --mode mcp --json -- \
node node_modules/@modelcontextprotocol/server-everything/dist/index.js stdio 2>mcp.log &
pid=$!
for _ in $(seq 1 50); do
grep -q '"event":"mcp-listening"' mcp.log && break
sleep 0.2
done
kill "$pid" 2>/dev/null || true
grep -q '"event":"mcp-listening"' mcp.log
grep -q 'http://127.0.0.1:' mcp.log
- name: Publish bridge.cjs to the tag's GitHub Release
if: startsWith(github.ref, 'refs/tags/stdio-bridge-v')
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release create "${GITHUB_REF_NAME}" dist/bridge.cjs --title "${GITHUB_REF_NAME}" --generate-notes