mirror of
https://github.com/anomalyco/opencode.git
synced 2026-10-25 23:30:04 +00:00
137 lines
6.8 KiB
Markdown
137 lines
6.8 KiB
Markdown
# OpenCode Update
|
|
|
|
The update Worker serves all selected artifacts for a channel.
|
|
|
|
```sh
|
|
curl 'https://opencode.ai/update/api/latest'
|
|
curl 'https://opencode.ai/update/api/latest/cli'
|
|
curl 'https://opencode.ai/update/api/latest/cli/npm'
|
|
```
|
|
|
|
The same Worker also serves the original `https://update.opencode.ai` hostname without
|
|
the `/update` prefix. Admin forms, pagination, and redirects preserve the request's mount.
|
|
|
|
## Desktop update feeds
|
|
|
|
Electron updater manifests are available at `/api/<channel>/desktop/<distribution>/<filename>`:
|
|
|
|
```sh
|
|
curl 'https://opencode.ai/update/api/beta/desktop/opencode/latest-mac.yml'
|
|
```
|
|
|
|
Use `latest.yml` for Windows, `latest-mac.yml` for macOS, `latest-linux.yml` for Linux x64,
|
|
and `latest-linux-arm64.yml` for Linux ARM64. The distribution selects the stored download
|
|
URLs (`opencode` or `github`). Each manifest includes the selected artifact's version,
|
|
file URLs, SHA-512 checksums, sizes, and release date. Existing minimum-version selection
|
|
and `current`/User-Agent handling also apply to these feeds.
|
|
|
|
## Channel rollouts
|
|
|
|
Set each channel's rollout duration in hours on the admin page. All channels default
|
|
to `0` (immediate); fractional hours are supported. For example, `6` makes a release
|
|
available to roughly half of IPs after three hours and all IPs after six hours.
|
|
|
|
Eligibility uses the original publication time (`time_created`) and a SHA-256 hash
|
|
of the channel and Cloudflare's `CF-Connecting-IP`. Each IP keeps the same rollout
|
|
position across releases in that channel. Requests without this header wait for
|
|
the full duration. The retired `next` channel is not configurable; `/api/next`
|
|
remains a compatibility alias for `/api/beta`, including its rollout settings.
|
|
|
|
Until the active release is eligible, callers receive the newest eligible artifact
|
|
published before it, for the same name and distribution. This also handles overlapping
|
|
rollouts. Earlier inactive releases can be fallbacks, including manually deactivated
|
|
releases; releases newer than the active release cannot. If no eligible artifact
|
|
exists, it is omitted from listings and individual artifact requests return 404.
|
|
|
|
Minimum releases bypass rollout for clients that need them, and identified clients
|
|
are not sent a fallback below their configured minimum. Rollout applies to all JSON
|
|
endpoints and desktop manifests. Responses, including unavailable artifacts, are not cached.
|
|
|
|
Duration changes apply immediately to existing releases. Manual activation uses the
|
|
original publication time too; set the duration to `0` to make it immediate.
|
|
Apply the `0004_channel_rollout.sql` migration before deploying.
|
|
|
|
## Minimum releases
|
|
|
|
Each channel/name/distribution can mark one retained artifact as `minimum`, independently
|
|
of its `active` artifact. Set or clear it from the admin page. Publishing a new active
|
|
release preserves the minimum marker.
|
|
|
|
Clients send their running version as `?current=<version>` and use the CLI's default
|
|
`User-Agent: opencode/<channel>/<version>/cli`. When `current` is absent, the service
|
|
parses that User-Agent or the older `opencode/<version>` format.
|
|
The caller's channel comes from the default User-Agent, or from a preview version
|
|
such as `0.0.0-beta-18955` when that channel is absent. If an identified caller channel
|
|
differs from the requested channel, the service serves the active release without
|
|
applying the minimum. Historical `next` and `beta` count as the same channel.
|
|
A caller below the minimum receives that exact
|
|
artifact; callers at or above it receive the active artifact. An unparseable caller
|
|
version receives the minimum. Requests with neither version source receive the active
|
|
artifact. All three public API paths apply the same selection and use `Cache-Control:
|
|
no-store` because responses can depend on the User-Agent.
|
|
|
|
Version comparison uses semver, normalizing preview run numbers to numeric prerelease
|
|
identifiers and historical `next` versions to `beta`. The retired `/api/next`
|
|
channel transparently resolves to `beta` for older clients.
|
|
|
|
Choose a minimum that older clients can install and that can itself consume the active
|
|
release. For the CLI package migration, retain a package-aware release published as
|
|
`@opencode-ai/cli` as the minimum before activating releases under `@opencode/cli`.
|
|
|
|
Both admin mounts must be protected by the same Cloudflare Access self-hosted application:
|
|
|
|
- Public hostname/path: `update.opencode.ai/admin*`
|
|
- Public hostname/path: `opencode.ai/update/admin*`
|
|
- Policy: allow the OpenCode team identity group
|
|
|
|
Configure Access before deploying the new Worker route. The Worker has `workers_dev`
|
|
and preview URLs disabled; it is exposed through its custom hostname and the `/update` routes.
|
|
|
|
## Request logging
|
|
|
|
Every request reaching the Worker emits an unsampled event at request start to the shared production
|
|
Cloudflare lake stream through the `EVENTS` Pipelines binding. Events use
|
|
`source: "update"`, `type: "request"`, an ISO `timestamp`, and a `payload` containing
|
|
the method, path, `useragent`, `ip` (from Cloudflare's `CF-Connecting-IP` header),
|
|
country, and Cloudflare colo. The path is normalized without `/update` so both mounts
|
|
share the existing analytics paths. Query strings, request bodies, cookies, and authorization
|
|
headers are not included. Response status and duration are not recorded.
|
|
|
|
Delivery runs in `waitUntil` without delaying the response. Delivery failures are
|
|
logged but do not fail requests or retry; this is not lossless audit logging.
|
|
Requests blocked before reaching the Worker are not recorded.
|
|
|
|
The stream ID in `wrangler.jsonc` comes from the `lake.stream` output of the
|
|
`anomalyco/platform/production` Pulumi stack. Update the binding if that stream is
|
|
replaced. The stream is shared across release channels because the update service
|
|
has a single public deployment.
|
|
|
|
## Publishing
|
|
|
|
The publish workflow also registers direct binary downloads with distribution
|
|
`opencode`, after uploading every file to the public files bucket:
|
|
|
|
```sh
|
|
curl 'https://opencode.ai/update/api/dev/cli/opencode'
|
|
curl 'https://opencode.ai/update/api/dev/cli-node/opencode'
|
|
curl 'https://opencode.ai/update/api/latest/desktop/opencode'
|
|
```
|
|
|
|
`metadata.files` maps each filename to its direct
|
|
`https://opencode.ai/files/bin/<version>/<filename>` URL, SHA-256 checksum, and
|
|
byte size. Desktop records additionally contain `metadata.manifests`, with
|
|
the CDN URLs and the original Electron update checksums. Existing `npm`,
|
|
`github`, and `aur` distributions are published independently.
|
|
|
|
GitHub Actions publishes artifacts through `POST https://opencode.ai/update/api/publish`
|
|
using a short-lived OIDC token with audience `https://update.opencode.ai`. The original
|
|
hostname and token audience remain supported. The Worker accepts only tokens signed by
|
|
GitHub for repository ID `975734319`, owner ID `66570915`, and `.github/workflows/publish.yml`
|
|
on configured publishing refs.
|
|
|
|
Apply migrations and deploy from this directory:
|
|
|
|
```sh
|
|
bun run db:migrate
|
|
bun run deploy
|
|
```
|