diff --git a/packages/updates/README.md b/packages/updates/README.md index 79ac65a5cd0..7e205db484e 100644 --- a/packages/updates/README.md +++ b/packages/updates/README.md @@ -17,6 +17,10 @@ release preserves the minimum marker. Clients send their running version as `?current=` and use the CLI's default `User-Agent: opencode///cli`. When `current` is absent, the service parses that User-Agent or the older `opencode/` 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 diff --git a/packages/updates/src/index.ts b/packages/updates/src/index.ts index 3395c3e0922..2eb239fbc90 100644 --- a/packages/updates/src/index.ts +++ b/packages/updates/src/index.ts @@ -70,11 +70,13 @@ export default { } const resolved = resolveChannel(path[0]) - const agent = request.headers.get("User-Agent")?.match(/^opencode\/(?:[^/]+\/([^/]+)\/cli|(.*))$/) - const current = url.searchParams.get("current") ?? agent?.[1] ?? agent?.[2] - if (path.length === 1) return channel(env.DB, resolved, current) - if (path.length === 2) return artifactName(env.DB, resolved, path[1], current) - return artifactDistribution(env.DB, resolved, path[1], path[2], current) + const agent = request.headers.get("User-Agent")?.match(/^opencode\/(?:([^/]+)\/([^/]+)\/cli|(.*))$/) + const current = url.searchParams.get("current") ?? agent?.[2] ?? agent?.[3] + const source = agent?.[1] ?? current?.match(/^v?0\.0\.0-(.+)-\d+(?:\.\d+)?(?:\+.*)?$/)?.[1] + const caller = source === undefined || resolveChannel(source) === resolved ? current : undefined + if (path.length === 1) return channel(env.DB, resolved, caller) + if (path.length === 2) return artifactName(env.DB, resolved, path[1], caller) + return artifactDistribution(env.DB, resolved, path[1], path[2], caller) }, } satisfies ExportedHandler