-
Notifications
You must be signed in to change notification settings - Fork 0
feat(publish): unscoped relayflows CLI package #237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ on: | |
| description: Package to publish (single-package selections are dry-run only) | ||
| required: true | ||
| type: choice | ||
| options: [all, surface, sdk, runtime-linux-x64] | ||
| options: [all, surface, sdk, runtime-linux-x64, relayflows] | ||
| default: all | ||
| version: | ||
| description: Version bump type | ||
|
|
@@ -108,7 +108,26 @@ jobs: | |
| ./node_modules/.bin/tsc | ||
| node scripts/make-cli-executable.mjs | ||
| - name: Pack and assert SDK | ||
| id: sdk | ||
| run: node scripts/pack-release.mjs sdk | ||
| # relayflows only re-exposes the SDK's CLI under the unscoped name, so it | ||
| # builds against the packed SDK the same way the SDK builds against the | ||
| # packed surface — and it's cheap enough to smoke-test for real here | ||
| # rather than only asserting the tarball's shape in pack-release.mjs. | ||
| - name: Build relayflows CLI wrapper against packed SDK | ||
| env: | ||
| SDK_TARBALL: ${{ steps.sdk.outputs.tarball }} | ||
| working-directory: packages/relayflows | ||
| run: | | ||
| npm install --no-save --package-lock=false --ignore-scripts "$SDK_TARBALL" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On every real version bump where the new surface version is not already published, the “Build relayflows CLI wrapper against packed SDK” step fails here: Useful? React with 👍 / 👎. |
||
| test ! -L node_modules/@relayflows/sdk | ||
| report=$(node bin/flows.js check --json ../../testdata/hello-deterministic.flow.yaml) | ||
| echo "$report" | node -e ' | ||
| const report = JSON.parse(require("fs").readFileSync(0, "utf8")); | ||
| if (report.ok !== true) { console.error(report); process.exit(1); } | ||
| ' | ||
| - name: Pack and assert relayflows CLI wrapper | ||
| run: node scripts/pack-release.mjs relayflows | ||
| - name: Build relayflowd | ||
| working-directory: kernel | ||
| run: cargo build --locked --release -p relayflowd | ||
|
|
@@ -152,13 +171,19 @@ jobs: | |
| with: | ||
| name: build-output | ||
| path: dist/build-output | ||
| # relayflows is the one unscoped package, so `npm pack` names its tarball | ||
| # `relayflows-<version>.tgz`, not `relayflows-relayflows-<version>.tgz`. | ||
| - name: Restore built packages | ||
| env: | ||
| NEW_VERSION: ${{ needs.build.outputs.new_version }} | ||
| run: | | ||
| for package in surface sdk runtime-linux-x64; do | ||
| tar -xzf "dist/build-output/relayflows-${package}-${NEW_VERSION}.tgz" \ | ||
| --strip-components=1 -C "packages/$package" | ||
| for package in surface sdk runtime-linux-x64 relayflows; do | ||
| if [[ "$package" == relayflows ]]; then | ||
| tarball="relayflows-${NEW_VERSION}.tgz" | ||
| else | ||
| tarball="relayflows-${package}-${NEW_VERSION}.tgz" | ||
| fi | ||
| tar -xzf "dist/build-output/$tarball" --strip-components=1 -C "packages/$package" | ||
| done | ||
| # Repack and check EVERYTHING before the first publish. Tar archives | ||
| # preserve executable bits across Actions artifact upload/download. | ||
|
|
@@ -167,18 +192,24 @@ jobs: | |
| node scripts/pack-release.mjs surface | ||
| node scripts/pack-release.mjs sdk | ||
| node scripts/pack-release.mjs runtime-linux-x64 | ||
| - name: Publish to NPM (surface before SDK) | ||
| node scripts/pack-release.mjs relayflows | ||
| - name: Publish to NPM (surface before SDK, relayflows last) | ||
| env: | ||
| PACKAGE: ${{ inputs.package }} | ||
| NEW_VERSION: ${{ needs.build.outputs.new_version }} | ||
| DRY_RUN: ${{ inputs.dry_run }} | ||
| NPM_TAG: ${{ inputs.tag }} | ||
| run: | | ||
| for package in surface sdk runtime-linux-x64; do | ||
| for package in surface sdk runtime-linux-x64 relayflows; do | ||
| if [[ "$PACKAGE" != all && "$PACKAGE" != "$package" ]]; then continue; fi | ||
| if [[ "$package" == relayflows ]]; then | ||
| tarball="relayflows-${NEW_VERSION}.tgz" | ||
| else | ||
| tarball="relayflows-${package}-${NEW_VERSION}.tgz" | ||
| fi | ||
| args=() | ||
| if [[ "$DRY_RUN" == true ]]; then args+=(--dry-run); fi | ||
| npm publish "dist/publish/relayflows-${package}-${NEW_VERSION}.tgz" \ | ||
| npm publish "dist/publish/$tarball" \ | ||
| --access public --provenance --ignore-scripts --tag "$NPM_TAG" "${args[@]}" | ||
| done | ||
| - name: Regenerate release lockfiles | ||
|
|
@@ -188,17 +219,24 @@ jobs: | |
| run: | | ||
| npm install --prefix packages/surface --package-lock-only --ignore-scripts | ||
| npm install --prefix packages/sdk --package-lock-only --ignore-scripts --save-exact "@relayflows/surface@$NEW_VERSION" | ||
| npm install --prefix packages/relayflows --package-lock-only --ignore-scripts --save-exact "@relayflows/sdk@$NEW_VERSION" | ||
| node --input-type=module - <<'NODE' | ||
| import assert from 'node:assert/strict'; | ||
| import { readFileSync } from 'node:fs'; | ||
| const lock = JSON.parse(readFileSync('packages/sdk/package-lock.json', 'utf8')); | ||
| const surface = lock.packages['node_modules/@relayflows/surface']; | ||
| assert.equal(surface.version, process.env.NEW_VERSION); | ||
| assert.match(surface.resolved, /^https:\/\/registry\.npmjs\.org\//); | ||
| assert(!surface.link, 'release lockfile must resolve the published surface'); | ||
| const version = process.env.NEW_VERSION; | ||
| const check = (lockPath, depNodeModulesPath) => { | ||
| const lock = JSON.parse(readFileSync(lockPath, 'utf8')); | ||
| const dep = lock.packages[depNodeModulesPath]; | ||
| assert.equal(dep.version, version); | ||
| assert.match(dep.resolved, /^https:\/\/registry\.npmjs\.org\//); | ||
| assert(!dep.link, `release lockfile must resolve the published dependency (${lockPath})`); | ||
| }; | ||
| check('packages/sdk/package-lock.json', 'node_modules/@relayflows/surface'); | ||
| check('packages/relayflows/package-lock.json', 'node_modules/@relayflows/sdk'); | ||
| NODE | ||
| npm ci --prefix packages/surface --dry-run --ignore-scripts | ||
| npm ci --prefix packages/sdk --dry-run --ignore-scripts | ||
| npm ci --prefix packages/relayflows --dry-run --ignore-scripts | ||
| - name: Commit version bump and create tag | ||
| if: ${{ !inputs.dry_run }} | ||
| env: | ||
|
|
@@ -209,7 +247,8 @@ jobs: | |
| git config user.email 'actions@github.com' | ||
| git add packages/surface/package.json packages/surface/package-lock.json \ | ||
| packages/sdk/package.json packages/sdk/package-lock.json \ | ||
| packages/runtime-linux-x64/package.json | ||
| packages/runtime-linux-x64/package.json \ | ||
| packages/relayflows/package.json packages/relayflows/package-lock.json | ||
| if ! git diff --staged --quiet; then | ||
| git commit -m "chore(release): v${NEW_VERSION}" | ||
| fi | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # relayflows | ||
|
|
||
| The `flows` CLI, published under the unscoped name so the install is just: | ||
|
|
||
| ```sh | ||
| npm install -g relayflows | ||
| ``` | ||
|
|
||
| This package carries no logic of its own. It declares `@relayflows/sdk` as a | ||
| normal dependency and `bin/flows.js` forwards argv and stdio straight to that | ||
| dependency's `dist/cli.js`, resolved by filesystem path from this package's | ||
| own `node_modules` rather than by import specifier — the SDK's package | ||
| `exports` doesn't list that subpath, so a bare `import` would be refused. | ||
|
|
||
| Versioned and released in lockstep with `@relayflows/sdk`: the two always | ||
| carry the same version number, and this package pins its dependency to that | ||
| exact version rather than a range, so `npm install -g relayflows` always | ||
| resolves the SDK build it shipped with. | ||
|
|
||
| See `@relayflows/sdk` and `docs/SURFACE.md` for what the CLI actually does. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #!/usr/bin/env node | ||
| import { spawnSync } from 'node:child_process'; | ||
| import { existsSync } from 'node:fs'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| // Not `import '@relayflows/sdk/dist/cli.js'`: that subpath isn't in the | ||
| // SDK's package "exports", so specifier resolution would refuse it. Locating | ||
| // the installed dependency's real CLI file directly sidesteps that — this | ||
| // package's only job is finding it and forwarding argv/stdio. | ||
| const packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..'); | ||
| const sdkCli = join(packageRoot, 'node_modules', '@relayflows', 'sdk', 'dist', 'cli.js'); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
|
|
||
| if (!existsSync(sdkCli)) { | ||
| process.stderr.write( | ||
| `relayflows: could not find @relayflows/sdk at ${sdkCli}\n` + | ||
| 'Reinstall with `npm install -g relayflows`.\n', | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const result = spawnSync(process.execPath, [sdkCli, ...process.argv.slice(2)], { stdio: 'inherit' }); | ||
| process.exit(result.status ?? 1); | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { | ||
| "name": "relayflows", | ||
| "version": "2.0.1", | ||
| "description": "Relayflow v2 CLI. Installs the `flows` command — a thin wrapper around @relayflows/sdk, published under the unscoped name for `npm install -g relayflows`.", | ||
| "type": "module", | ||
| "license": "Apache-2.0", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/AgentWorkforce/flows.git", | ||
| "directory": "packages/relayflows" | ||
| }, | ||
| "files": [ | ||
| "bin" | ||
| ], | ||
| "bin": { | ||
| "flows": "./bin/flows.js" | ||
| }, | ||
| "dependencies": { | ||
| "@relayflows/sdk": "2.0.1" | ||
| }, | ||
| "engines": { | ||
| "node": ">=20" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: On every release that advances the version, this fresh CI install tries to fetch
@relayflows/surface@NEW_VERSIONfrom npm even though that version has not been published yet, so the relayflows build fails before its smoke test. Install the packed surface tarball alongsideSDK_TARBALL(for example, pass${{ steps.surface.outputs.tarball }}to thisnpm install).Prompt for AI agents