Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Contract

# Watch the contract this plugin maps against.
#
# BitRouter Cloud publishes its `GET /v1/models` response schema, generated
# from the Rust types that serialize the response. This job re-vendors that
# schema and, when it has moved, opens a pull request carrying the diff.
#
# The point is not the schema file. It is `test/schema.test.ts`, which fails
# when a field appears that nobody has decided about, or disappears while this
# package still reads it. A dropped field is the dangerous direction: nothing
# errors, the mapping silently falls back to a default, and the catalog goes
# quietly wrong. That is not hypothetical — it is what happened when this
# package read `context_window`.
#
# Deliberately not part of the pull-request build. That build has to be
# offline and deterministic to be worth gating merges on; this one talks to a
# live service, so it runs on a clock where a flake costs nothing.
on:
schedule:
- cron: "0 5 * * *"
workflow_dispatch:

permissions: {}

jobs:
refresh:
name: re-vendor the published schema
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v6
with: { persist-credentials: false }
- uses: actions/setup-node@v4
with: { node-version: "20", cache: npm }
- run: npm ci

- name: re-vendor schema/models.schema.json
run: npm run schema:refresh

# A pull request opened with the default GITHUB_TOKEN does not trigger
# workflows — GitHub suppresses that to stop a job from re-triggering
# itself. Which would leave this pull request with no checks at all, and
# a required check that never reports blocks a merge forever. So it
# wants a real token. Set CONTRACT_PR_TOKEN to a fine-grained PAT (or an
# app installation token) with contents:write and pull-requests:write on
# this repository.
- uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
token: ${{ secrets.CONTRACT_PR_TOKEN }}
branch: chore/contract-refresh
base: main
add-paths: schema/models.schema.json
commit-message: "chore: re-vendor BitRouter Cloud's /v1/models schema"
title: "chore: BitRouter Cloud's /v1/models contract has moved"
labels: contract
body: |
`schema/models.schema.json` no longer matches the schema BitRouter
Cloud publishes at <https://api.bitrouter.ai/openapi.json>.

The diff is the contract change. What matters is whether the suite
still passes on it:

- **Green** — the change is one this package already tolerates.
Merge it.
- **Red on the field-set assertion** — a field appeared or
vanished. Decide what to do with it and record the decision in
`ACKNOWLEDGED` in `test/schema.test.ts`.
- **Red on fixture conformance** — `test/fixtures/cloud-models.json`
predates the change. Recapture it:
`curl -s https://api.bitrouter.ai/v1/models`.
- **Red on tiered pricing** — a fixture row with `context_tiers`
is gone from the catalog. Pick another from the same call.

# After the pull request, not before: if the new contract breaks the
# assertions, this job should go red *and* the pull request should still
# exist to show why.
- name: check the vendored contract against this package's assumptions
run: npm test
76 changes: 76 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Publish

# The human gate.
#
# Everything else in this repository is allowed to merge itself: a Dependabot
# bump or an automated compatibility fix that goes green on `main` needs no
# review, because `main` reaches nobody. This workflow is the step that does
# reach somebody, so it is the one a person has to perform — by drafting a
# GitHub release and pressing publish.
#
# Deliberately NOT `on: push: branches: [main]`. That trigger would collapse
# the merge gate and the release gate into one, and the whole safety of
# auto-merge rests on them being separate.
on:
release:
types: [published]

permissions: {}

jobs:
publish:
name: publish to npm
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
# npm provenance: the registry attests that this tarball was built by
# this workflow from this commit, which is checkable by anyone.
id-token: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.release.tag_name }}
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
registry-url: https://registry.npmjs.org

# A release tag that disagrees with package.json publishes a version
# nobody asked for, under a git ref that does not contain it. Cheaper to
# refuse here than to deprecate afterwards.
- name: check the tag against package.json
env:
TAG: ${{ github.event.release.tag_name }}
run: |
set -euo pipefail
PKG=$(node -p "require('./package.json').version")
if [ "${TAG#v}" != "$PKG" ]; then
echo "::error::release tag '$TAG' does not match package.json version '$PKG'"
exit 1
fi
echo "publishing $PKG from $TAG"

# The same checks `main` had to pass, run once more against the tagged
# tree. A release can be cut from any ref, so being green on `main` is
# not by itself evidence about what is in the tarball.
- run: npm ci
- run: npm run build
- run: npx tsc --noEmit -p tsconfig.test.json
- run: npm test

# A prerelease goes out under the `next` tag, so `npm i @bitrouter/opencode`
# keeps resolving to the last stable one.
- name: publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
PRERELEASE: ${{ github.event.release.prerelease }}
run: |
set -euo pipefail
if [ "$PRERELEASE" = "true" ]; then
npm publish --provenance --access public --tag next
else
npm publish --provenance --access public
fi
59 changes: 59 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
"build": "tsc",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"prepublishOnly": "npm run build"
"prepublishOnly": "npm run build",
"schema:refresh": "node scripts/refresh-schema.mjs",
"schema:check": "node scripts/refresh-schema.mjs --check"
},
"peerDependencies": {
"@opencode-ai/plugin": ">=1.18.0"
Expand All @@ -52,6 +54,7 @@
"@opencode-ai/plugin": "^1.18.18",
"@opencode-ai/sdk": "^1.18.18",
"@types/node": "^20.0.0",
"ajv": "^8.20.0",
"typescript": "^5.4.0",
"vitest": "^1.6.0"
}
Expand Down
Loading
Loading