Compare commits

..

1 Commits

Author SHA1 Message Date
Aiden Cline 95136042c7 fix(provider): gate Azure reasoning effort by endpoint 2026-08-03 19:05:48 +00:00
44 changed files with 232 additions and 282 deletions
+27
View File
@@ -252,6 +252,33 @@ These are not strictly enforced, they are just general guidelines:
For net-new functionality, start with a design conversation. Open an issue describing the problem, your proposed approach (optional), and why it belongs in OpenCode. The core team will help decide whether it should move forward; please wait for that approval instead of opening a feature PR directly.
## Trust & Vouch System
This project uses [vouch](https://github.com/mitchellh/vouch) to manage contributor trust. The vouch list is maintained in [`.github/VOUCHED.td`](.github/VOUCHED.td).
### How it works
- **Vouched users** are explicitly trusted contributors.
- **Denounced users** are explicitly blocked. Issues and pull requests from denounced users are automatically closed. If you have been denounced, you can request to be unvouched by reaching out to a maintainer on [Discord](https://opencode.ai/discord)
- **Everyone else** can participate normally — you don't need to be vouched to open issues or PRs.
### For maintainers
Collaborators with write access can manage the vouch list by commenting on any issue:
- `vouch` — vouch for the issue author
- `vouch @username` — vouch for a specific user
- `denounce` — denounce the issue author
- `denounce @username` — denounce a specific user
- `denounce @username <reason>` — denounce with a reason
- `unvouch` / `unvouch @username` — remove someone from the list
Changes are committed automatically to `.github/VOUCHED.td`.
### Denouncement policy
Denouncement is reserved for users who repeatedly submit low-quality AI-generated contributions, spam, or otherwise act in bad faith. It is not used for disagreements or honest mistakes.
## Issue Requirements
All issues **must** use one of our issue templates:
+28 -28
View File
@@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@@ -96,7 +96,7 @@
},
"packages/cli": {
"name": "@opencode-ai/cli",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"lildax": "./bin/lildax.cjs",
},
@@ -144,7 +144,7 @@
},
"packages/codemode": {
"name": "@opencode-ai/codemode",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@@ -158,7 +158,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -194,7 +194,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -221,7 +221,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/openai": "3.0.48",
@@ -243,7 +243,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -267,7 +267,7 @@
},
"packages/console/support": {
"name": "@opencode-ai/console-support",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode-ai/console-core": "workspace:*",
@@ -287,7 +287,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"opencode": "./bin/opencode",
},
@@ -381,7 +381,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"drizzle-orm": "catalog:",
@@ -435,7 +435,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -449,7 +449,7 @@
},
"packages/effect-sqlite-node": {
"name": "@opencode-ai/effect-sqlite-node",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"effect": "catalog:",
},
@@ -461,7 +461,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -493,7 +493,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -509,7 +509,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@effect/platform-node": "4.0.0-beta.83",
"@effect/platform-node-shared": "4.0.0-beta.83",
@@ -540,7 +540,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/schema": "workspace:*",
"@smithy/eventstream-codec": "4.2.14",
@@ -559,7 +559,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.18.12",
"version": "1.18.11",
"bin": {
"opencode": "./bin/opencode",
},
@@ -690,7 +690,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode-ai/sdk": "workspace:*",
@@ -766,7 +766,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -781,7 +781,7 @@
},
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
@@ -796,7 +796,7 @@
},
"packages/session-ui": {
"name": "@opencode-ai/session-ui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
@@ -840,7 +840,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -853,7 +853,7 @@
},
"packages/stats/app": {
"name": "@opencode-ai/stats-app",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@@ -887,7 +887,7 @@
},
"packages/stats/core": {
"name": "@opencode-ai/stats-core",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@@ -906,7 +906,7 @@
},
"packages/stats/server": {
"name": "@opencode-ai/stats-server",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@@ -948,7 +948,7 @@
},
"packages/tui": {
"name": "@opencode-ai/tui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
@@ -975,7 +975,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@@ -1027,7 +1027,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.18.12",
"version": "1.18.11",
"description": "",
"type": "module",
"exports": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/cli",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"bin": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/codemode",
"version": "1.18.12",
"version": "1.18.11",
"description": "Effect-native confined code execution over schema-described tools",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+13 -35
View File
@@ -59,30 +59,7 @@ export namespace Referral {
const accountID = Actor.account()
const code = await ensureCode(workspaceID)
const rows = await Database.use(async (tx) => {
const [rewards, invites, inviteeReferral, inviteeRewards] = await Promise.all([
tx
.select({
referralID: ReferralRewardTable.referralID,
workspaceID: ReferralRewardTable.workspaceID,
referralWorkspaceID: ReferralTable.workspaceID,
inviteeEmail: AuthTable.subject,
amount: ReferralRewardTable.amount,
timeCreated: ReferralRewardTable.timeCreated,
timeApplied: ReferralRewardTable.timeApplied,
})
.from(ReferralRewardTable)
.innerJoin(ReferralTable, eq(ReferralTable.id, ReferralRewardTable.referralID))
.innerJoin(
AuthTable,
and(eq(AuthTable.accountID, ReferralTable.inviteeAccountID), eq(AuthTable.provider, "email")),
)
.where(
and(
eq(ReferralRewardTable.workspaceID, workspaceID),
isNull(ReferralRewardTable.timeDeleted),
isNull(ReferralTable.timeDeleted),
),
),
const [invites, inviteeReferral] = await Promise.all([
tx
.select({ id: ReferralTable.id, inviteeEmail: AuthTable.subject, timeCreated: ReferralTable.timeCreated })
.from(ReferralTable)
@@ -106,19 +83,20 @@ export namespace Referral {
.where(and(eq(ReferralTable.inviteeAccountID, accountID), isNull(ReferralTable.timeDeleted)))
.orderBy(asc(UserTable.timeCreated))
.then((rows) => rows.find((row) => row.inviterEmail) ?? rows[0]),
tx
.select({ referralID: ReferralRewardTable.referralID })
.from(ReferralRewardTable)
.innerJoin(ReferralTable, eq(ReferralTable.id, ReferralRewardTable.referralID))
.where(
and(
eq(ReferralTable.inviteeAccountID, accountID),
isNull(ReferralRewardTable.timeDeleted),
isNull(ReferralTable.timeDeleted),
),
),
])
// Hide reward history until the referral_id index can be deployed and this lookup restored.
const rewards: {
referralID: string
workspaceID: string
referralWorkspaceID: string
inviteeEmail: string
amount: number
timeCreated: Date
timeApplied: Date | null
}[] = []
// Hide pending invitee rewards until the referral_id index can be deployed and this lookup restored.
const inviteeRewards = inviteeReferral ? [{ referralID: inviteeReferral.id }] : []
return { inviteeReferral, inviteeRewards, invites, rewards }
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.18.12",
"version": "1.18.11",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.18.12",
"version": "1.18.11",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-support",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/effect-sqlite-node",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.18.12",
"version": "1.18.11",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/http-recorder",
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.12",
"version": "1.18.11",
"name": "opencode",
"type": "module",
"license": "MIT",
+34 -26
View File
@@ -551,32 +551,6 @@ export async function XaiAuthPlugin(input: PluginInput, options: XaiAuthPluginOp
{
label: "xAI Grok OAuth (SuperGrok Subscription)",
type: "oauth",
authorize: async () => {
const device = await requestDeviceCode(options)
const browserUrl = device.verification_uri_complete ?? device.verification_uri
return {
url: browserUrl,
instructions: `Open ${device.verification_uri} on any device and enter code: ${device.user_code}`,
method: "auto" as const,
callback: async () => {
try {
const tokens = await pollDeviceCodeToken(device, options)
return {
type: "success" as const,
refresh: tokens.refresh_token,
access: tokens.access_token,
expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,
}
} catch (err) {
return { type: "failed" as const }
}
},
}
},
},
{
label: "xAI Grok OAuth (Local Callback)",
type: "oauth",
authorize: async () => {
await startOAuthServer()
const pkce = await generatePKCE()
@@ -608,6 +582,40 @@ export async function XaiAuthPlugin(input: PluginInput, options: XaiAuthPluginOp
}
},
},
{
// RFC 8628 device-code flow. The CLI prints a verification URL
// and a short user_code that the user enters in a browser on
// any device. No loopback callback server runs on the CLI host,
// so this works on VPS / SSH / Docker / CI / WSL / any
// environment where 127.0.0.1:56121 isn't reachable from the
// user's browser. Defends the only attack surface (the polling
// loop) with the standard authorization_pending / slow_down
// backoff and a hard deadline from xAI's `expires_in`.
label: "xAI Grok OAuth (Headless / Remote / VPS)",
type: "oauth",
authorize: async () => {
const device = await requestDeviceCode(options)
const browserUrl = device.verification_uri_complete ?? device.verification_uri
return {
url: browserUrl,
instructions: `Open ${device.verification_uri} on any device and enter code: ${device.user_code}`,
method: "auto" as const,
callback: async () => {
try {
const tokens = await pollDeviceCodeToken(device, options)
return {
type: "success" as const,
refresh: tokens.refresh_token,
access: tokens.access_token,
expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,
}
} catch (err) {
return { type: "failed" as const }
}
},
}
},
},
{
label: "Manually enter API Key",
type: "api",
@@ -1270,17 +1270,6 @@ export function options(input: {
result["gateway"] = { caching: "auto" }
}
// Any gpt version above 5.4 in combination with azure does not support reasoningEffort
// so we should return early here.
const [, gptMajorVersion, gptMinorVersion] = input.model.api.id.match(/gpt-(\d+)\.(\d+)/) ?? []
const isGpt55OrNewer = Number(gptMajorVersion) > 5 || (Number(gptMajorVersion) === 5 && Number(gptMinorVersion) >= 5)
if (input.model.api.npm === "@ai-sdk/azure" && input.providerOptions?.useCompletionUrls) {
if (!isGpt55OrNewer) {
result["reasoningEffort"] = "medium"
}
return result
}
if (input.model.api.id.includes("gpt-5") && !input.model.api.id.includes("gpt-5-chat")) {
if (!input.model.api.id.includes("gpt-5-pro")) {
result["reasoningEffort"] = "medium"
@@ -93,6 +93,7 @@ export const prepare = Effect.fn("LLMRequestPrep.prepare")(function* (input: Pre
input.model.api.npm === "@ai-sdk/azure" &&
(input.provider.options.useCompletionUrls || input.model.options.useCompletionUrls || options.useCompletionUrls)
) {
delete options.reasoningEffort
delete options.reasoningSummary
delete options.include
}
+10 -10
View File
@@ -111,7 +111,7 @@ describe("plugin.xai", () => {
).toEqual({})
expect(hooks.auth!.methods.map((m) => [m.type, m.label])).toEqual([
["oauth", "xAI Grok OAuth (SuperGrok Subscription)"],
["oauth", "xAI Grok OAuth (Local Callback)"],
["oauth", "xAI Grok OAuth (Headless / Remote / VPS)"],
["api", "Manually enter API Key"],
])
})
@@ -424,11 +424,11 @@ describe("plugin.xai", () => {
return new Response("unexpected request", { status: 500 })
})
const hooks = await XaiAuthPlugin({} as any, serverOptions(server))
const oauth = hooks.auth!.methods.find(
const headless = hooks.auth!.methods.find(
(m): m is Extract<typeof m, { type: "oauth" }> =>
m.type === "oauth" && m.label === "xAI Grok OAuth (SuperGrok Subscription)",
m.type === "oauth" && m.label === "xAI Grok OAuth (Headless / Remote / VPS)",
)!
const result = await oauth.authorize!()
const result = await headless.authorize!()
expect(result.method).toBe("auto")
expect(result.url).toBe("https://x.ai/device?user_code=ABCD-1234")
@@ -448,11 +448,11 @@ describe("plugin.xai", () => {
}
return new Response("unexpected request", { status: 500 })
})
const oauth = (await XaiAuthPlugin({} as any, serverOptions(server))).auth!.methods.find(
const headless = (await XaiAuthPlugin({} as any, serverOptions(server))).auth!.methods.find(
(m): m is Extract<typeof m, { type: "oauth" }> =>
m.type === "oauth" && m.label === "xAI Grok OAuth (SuperGrok Subscription)",
m.type === "oauth" && m.label === "xAI Grok OAuth (Headless / Remote / VPS)",
)!
expect((await oauth.authorize!()).url).toBe("https://x.ai/device")
expect((await headless.authorize!()).url).toBe("https://x.ai/device")
})
test("requestDeviceCode posts form body, validates fields, and surfaces endpoint errors", async () => {
@@ -610,11 +610,11 @@ describe("plugin.xai", () => {
}
return Response.json({ error: "access_denied" }, { status: 400 })
})
const oauth = (await XaiAuthPlugin({} as any, serverOptions(server))).auth!.methods.find(
const headless = (await XaiAuthPlugin({} as any, serverOptions(server))).auth!.methods.find(
(m): m is Extract<typeof m, { type: "oauth" }> =>
m.type === "oauth" && m.label === "xAI Grok OAuth (SuperGrok Subscription)",
m.type === "oauth" && m.label === "xAI Grok OAuth (Headless / Remote / VPS)",
)!
expect(await ((await oauth.authorize!()) as any).callback()).toEqual({ type: "failed" })
expect(await ((await headless.authorize!()) as any).callback()).toEqual({ type: "failed" })
})
})
})
@@ -252,7 +252,7 @@ describe("ProviderTransform.options - setCacheKey", () => {
expect(result.promptCacheKey).toBeUndefined()
})
test("should keep the Azure cache key for gpt-5.5 early return", () => {
test("should keep the Azure cache key for gpt-5.5 Responses defaults", () => {
const result = ProviderTransform.options({
model: {
...mockModel,
@@ -525,7 +525,7 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
expect(result.include).toBeUndefined()
})
test("azure chat completions omit Responses-only reasoning options after variants merge", async () => {
test("azure chat completions omit unsupported reasoning options after variants merge", async () => {
const model = {
...createGpt5Model("gpt-5.4"),
id: "azure/gpt-5.4",
@@ -580,7 +580,7 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
isWorkflow: false,
}),
)
expect(result.params.options.reasoningEffort).toBe("high")
expect(result.params.options.reasoningEffort).toBeUndefined()
expect(result.params.options.reasoningSummary).toBeUndefined()
expect(result.params.options.include).toBeUndefined()
expect(result.tools.lookup.strict).toBe(false)
@@ -681,34 +681,15 @@ describe("ProviderTransform.options - gpt-5 reasoningEffort", () => {
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.5 should NOT set reasoningEffort for the completions API", () => {
test("gpt-5.5 should set Responses reasoning options", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.5"),
sessionID,
providerOptions: { useCompletionUrls: true },
})
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.6 should NOT set reasoningEffort for the completions API", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.6"),
sessionID,
providerOptions: { useCompletionUrls: true },
})
expect(result.reasoningEffort).toBeUndefined()
})
test("gpt-5.6 should set reasoningEffort for the responses API", () => {
const result = ProviderTransform.options({
model: createModel("gpt-5.6"),
sessionID,
providerOptions: {},
})
expect(result.reasoningEffort).toBe("medium")
expect(result.reasoningSummary).toBe("auto")
})
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/server",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/session-ui",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+5 -32
View File
@@ -255,16 +255,8 @@ function useFileViewer(config: ViewerConfig) {
if (!dragMoved) {
pendingSelectionEnd = false
const selected = config.buildClickSelection()
const next =
selected &&
lastSelection?.start === selected.start &&
lastSelection.end === selected.end &&
lastSelection.side === selected.side &&
(lastSelection.endSide ?? lastSelection.side) === (selected.endSide ?? selected.side)
? null
: selected
if (next !== undefined) config.setSelectedLines(next)
config.onLineSelectionEnd(next === undefined ? lastSelection : next)
if (selected) config.setSelectedLines(selected)
config.onLineSelectionEnd(lastSelection)
dragStart = undefined
dragEnd = undefined
dragMoved = false
@@ -299,29 +291,10 @@ function useFileViewer(config: ViewerConfig) {
createEffect(() => {
rendered()
const ranges = config.commentedLines()
const root = getRoot()
if (!root) return
if (ranges.length === 0) {
requestAnimationFrame(() => {
const root = getRoot()
if (!root) return
config.markCommented(root, ranges)
return
}
let frame: number | undefined
const mark = () => {
if (frame !== undefined) cancelAnimationFrame(frame)
frame = requestAnimationFrame(() => {
frame = undefined
config.markCommented(root, ranges)
})
}
const observer = new MutationObserver(mark)
observer.observe(root, { childList: true, subtree: true })
mark()
onCleanup(() => {
observer.disconnect()
if (frame !== undefined) cancelAnimationFrame(frame)
})
})
+29 -61
View File
@@ -26,19 +26,30 @@ const unsafeCSS = `
color-mix(in lab, var(--diffs-bg) 33.333%, var(--diffs-deletion-base)),
color-mix(in lab, var(--diffs-bg) 60%, var(--diffs-deletion-base))
);
--diffs-bg-deletion-number-override: var(--diffs-bg-deletion-override);
--diffs-bg-addition-override: light-dark(
color-mix(in lab, var(--diffs-bg) 33.333%, var(--diffs-addition-base)),
color-mix(in lab, var(--diffs-bg) 60%, var(--diffs-addition-base))
);
--diffs-bg-addition-number-override: var(--diffs-bg-addition-override);
--diffs-selection-base: var(--v2-background-bg-accent);
--diffs-selection-number-fg: var(--v2-text-text-accent);
--diffs-comment-bg: rgb(from var(--v2-background-bg-accent) r g b / 0.06);
--diffs-selection-base: var(--surface-warning-strong);
--diffs-selection-border: var(--border-warning-base);
--diffs-selection-number-fg: #1c1917;
/* Use explicit alpha instead of color-mix(..., transparent) to avoid Safari's non-premultiplied interpolation bugs. */
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--diffs-selection-base) r g b / 0.2));
--diffs-bg-selection-number: var(--diffs-bg-selection-number-override, var(--diffs-bg-selection));
--diffs-bg-selection-text: rgb(from var(--diffs-selection-base) r g b / 0.2);
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--surface-warning-base) r g b / 0.65));
--diffs-bg-selection-number: var(
--diffs-bg-selection-number-override,
rgb(from var(--surface-warning-base) r g b / 0.85)
);
--diffs-bg-selection-text: rgb(from var(--surface-warning-strong) r g b / 0.2);
}
:host([data-color-scheme='dark']) [data-diff],
:host([data-color-scheme='dark']) [data-file] {
--diffs-selection-number-fg: #fdfbfb;
--diffs-bg-selection: var(--diffs-bg-selection-override, rgb(from var(--solaris-dark-6) r g b / 0.65));
--diffs-bg-selection-number: var(
--diffs-bg-selection-number-override,
rgb(from var(--solaris-dark-6) r g b / 0.85)
);
}
[data-diff] ::selection,
@@ -46,34 +57,6 @@ const unsafeCSS = `
background-color: var(--diffs-bg-selection-text);
}
[data-indicators='bars'] [data-column-number][data-line-type='change-addition']::before,
[data-indicators='bars'] [data-column-number][data-line-type='change-deletion']::before {
width: 2px;
}
[data-indicators='bars'] [data-column-number][data-line-type='change-deletion']::before {
background-image: none;
background-color: var(--diffs-deletion-base);
}
[data-background] [data-column-number] {
--mix-light: 88%;
--mix-dark: 80%;
}
[data-diff-type='split'] [data-additions],
[data-diff-type='split'] [data-additions] [data-gutter],
[data-diff-type='split'] [data-deletions],
[data-diff-type='split'] [data-deletions] [data-content] {
border-left: 0;
border-right: 0;
}
[data-content-buffer] {
background-image: none;
background-color: var(--diffs-bg-context-gutter);
}
::highlight(opencode-find) {
background-color: rgb(from var(--surface-warning-base) r g b / 0.35);
}
@@ -100,24 +83,22 @@ const unsafeCSS = `
color: var(--diffs-selection-number-fg);
}
[data-diff] [data-line-annotation],
[data-diff] [data-gutter-buffer='annotation'],
[data-file] [data-line-annotation],
[data-file] [data-gutter-buffer='annotation'] {
--diffs-annotation-bg: var(--diffs-comment-bg);
--diffs-computed-decoration-bg: var(--diffs-comment-bg);
--diffs-computed-diff-line-bg: var(--diffs-comment-bg);
--diffs-computed-selected-line-bg: var(--diffs-comment-bg);
--diffs-line-bg: var(--diffs-comment-bg);
background-color: var(--diffs-comment-bg);
[data-diff] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] {
box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection);
}
[data-file] [data-line-annotation][data-comment-selected]:not([data-selected-line]) [data-annotation-content] {
box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection);
}
[data-diff] [data-line][data-selected-line] {
background-color: var(--diffs-bg-selection);
box-shadow: inset 2px 0 0 var(--diffs-selection-border);
}
[data-file] [data-line][data-selected-line] {
background-color: var(--diffs-bg-selection);
box-shadow: inset 2px 0 0 var(--diffs-selection-border);
}
[data-diff] [data-column-number][data-selected-line] {
@@ -137,19 +118,6 @@ const unsafeCSS = `
color: var(--diffs-selection-number-fg);
}
@media (pointer: fine) {
[data-gutter-utility-slot] {
opacity: 0;
pointer-events: none;
}
[data-column-number][data-hovered] [data-gutter-utility-slot],
[data-gutter-utility-slot]:focus-within {
opacity: 1;
pointer-events: auto;
}
}
/* The deletion word-diff emphasis is stronger than additions; soften it while selected so the selection highlight reads consistently. */
[data-diff] [data-line][data-line-type='change-deletion'][data-selected-line] {
--diffs-bg-deletion-emphasis: light-dark(
@@ -165,6 +133,7 @@ const unsafeCSS = `
height: 24px;
}
[data-column-number] {
background-color: var(--diffs-bg);
cursor: default !important;
}
@@ -213,6 +182,5 @@ export const styleVariables = {
"--diffs-font-features": "var(--font-family-mono--font-feature-settings)",
"--diffs-header-font-family": "var(--font-family-sans)",
"--diffs-gap-block": 0,
"--diffs-gap-style": 0,
"--diffs-min-number-column-width": "3ch",
"--diffs-min-number-column-width": "4ch",
}
@@ -151,10 +151,7 @@ export function createLineCommentControllerV2<T extends LineCommentShape>(props:
}
: undefined
},
onMouseEnter: () => {
if (note.commenting()) return
note.hoverComment(comment.selection)
},
onMouseEnter: () => note.hoverComment(comment.selection),
onClick: () => {
if (note.isEditing(comment.id)) return
note.toggleComment(comment.id, comment.selection)
@@ -167,14 +164,10 @@ export function createLineCommentControllerV2<T extends LineCommentShape>(props:
},
selection: formatSelectedLineLabel(range, i18n.t),
onInput: note.setDraft,
onCancel: () => {
note.cancelDraft()
note.select(null)
},
onCancel: note.cancelDraft,
onSubmit: (comment) => {
props.onSubmit({ comment, selection: cloneSelectedLineRange(range) })
note.cancelDraft()
note.select(null)
},
cancelLabel: i18n.t("ui.lineComment.cancel"),
submitLabel: i18n.t("ui.lineComment.submit"),
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-app",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-core",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-server",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/tui",
"version": "1.18.12",
"version": "1.18.11",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.18.12",
"version": "1.18.11",
"type": "module",
"license": "MIT",
"repository": {
@@ -1,3 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M728.039 234C819.325 234 893.323 308.62 893.323 400.668C893.323 492.716 819.325 567.336 728.039 567.336L891.984 732.656C912.81 753.655 898.061 789.56 868.613 789.56H397.472C245.333 789.56 122 665.193 122 511.78C122 358.367 245.333 234 397.472 234H728.039ZM397.472 345.112C306.189 345.112 232.189 419.732 232.189 511.78C232.189 603.828 306.189 678.448 397.472 678.448C488.756 678.448 562.756 603.828 562.756 511.78C562.756 419.732 488.756 345.112 397.472 345.112Z" fill="currentColor" transform="scale(0.0234375)"/>
<path d="M3.10913 12.07C3.65512 12.07 5.76627 11.5988 6.85825 10.98C7.95023 10.3612 7.95023 10.3612 10.207 8.75965C13.0642 6.73196 15.0845 7.41088 18.3968 7.41088" fill="currentColor"/>
<path d="M3.10913 12.07C3.65512 12.07 5.76627 11.5988 6.85825 10.98C7.95023 10.3612 7.95023 10.3612 10.207 8.75965C13.0642 6.73196 15.0845 7.41088 18.3968 7.41088" stroke="currentColor" stroke-width="3.27593"/>
<path d="M21.6 7.43108L16.0037 10.6622V4.20001L21.6 7.43108Z" fill="currentColor" stroke="currentColor" stroke-width="0.0363992"/>
<path d="M3 12.072C3.54599 12.072 5.65714 12.5432 6.74912 13.162C7.8411 13.7808 7.8411 13.7808 10.0978 15.3823C12.9551 17.41 14.9753 16.7311 18.2877 16.7311" fill="currentColor"/>
<path d="M3 12.072C3.54599 12.072 5.65714 12.5432 6.74912 13.162C7.8411 13.7808 7.8411 13.7808 10.0978 15.3823C12.9551 17.41 14.9753 16.7311 18.2877 16.7311" stroke="currentColor" stroke-width="3.27593"/>
<path d="M21.4909 16.7109L15.8945 13.4798V19.942L21.4909 16.7109Z" fill="currentColor" stroke="currentColor" stroke-width="0.0363992"/>
</svg>

Before

Width:  |  Height:  |  Size: 627 B

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -366,9 +366,34 @@
</symbol>
<symbol viewBox="0 0 24 24" fill="none" id="openrouter">
<path
d="M728.039 234C819.325 234 893.323 308.62 893.323 400.668C893.323 492.716 819.325 567.336 728.039 567.336L891.984 732.656C912.81 753.655 898.061 789.56 868.613 789.56H397.472C245.333 789.56 122 665.193 122 511.78C122 358.367 245.333 234 397.472 234H728.039ZM397.472 345.112C306.189 345.112 232.189 419.732 232.189 511.78C232.189 603.828 306.189 678.448 397.472 678.448C488.756 678.448 562.756 603.828 562.756 511.78C562.756 419.732 488.756 345.112 397.472 345.112Z"
d="M3.10913 12.07C3.65512 12.07 5.76627 11.5988 6.85825 10.98C7.95023 10.3612 7.95023 10.3612 10.207 8.75965C13.0642 6.73196 15.0845 7.41088 18.3968 7.41088"
fill="currentColor"
transform="scale(0.0234375)"
></path>
<path
d="M3.10913 12.07C3.65512 12.07 5.76627 11.5988 6.85825 10.98C7.95023 10.3612 7.95023 10.3612 10.207 8.75965C13.0642 6.73196 15.0845 7.41088 18.3968 7.41088"
stroke="currentColor"
stroke-width="3.27593"
></path>
<path
d="M21.6 7.43108L16.0037 10.6622V4.20001L21.6 7.43108Z"
fill="currentColor"
stroke="currentColor"
stroke-width="0.0363992"
></path>
<path
d="M3 12.072C3.54599 12.072 5.65714 12.5432 6.74912 13.162C7.8411 13.7808 7.8411 13.7808 10.0978 15.3823C12.9551 17.41 14.9753 16.7311 18.2877 16.7311"
fill="currentColor"
></path>
<path
d="M3 12.072C3.54599 12.072 5.65714 12.5432 6.74912 13.162C7.8411 13.7808 7.8411 13.7808 10.0978 15.3823C12.9551 17.41 14.9753 16.7311 18.2877 16.7311"
stroke="currentColor"
stroke-width="3.27593"
></path>
<path
d="M21.4909 16.7109L15.8945 13.4798V19.942L21.4909 16.7109Z"
fill="currentColor"
stroke="currentColor"
stroke-width="0.0363992"
></path>
</symbol>
<symbol viewBox="0 0 24 24" fill="none" id="opencode">

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 276 KiB

+2 -4
View File
@@ -41,8 +41,7 @@
"syntax-type": "var(--v2-purple-800)",
"syntax-constant": "#007b80",
"syntax-critical": "var(--v2-red-800)",
"syntax-diff-add": "var(--v2-state-fg-success)",
"syntax-diff-delete": "var(--v2-state-fg-danger)",
"syntax-diff-delete": "#ff8c00",
"syntax-diff-unknown": "#a753ae",
"surface-critical-base": "#FFF2F0"
},
@@ -276,8 +275,7 @@
"syntax-type": "var(--v2-purple-400)",
"syntax-constant": "#93e9f6",
"syntax-critical": "var(--v2-red-400)",
"syntax-diff-add": "var(--v2-state-fg-success)",
"syntax-diff-delete": "var(--v2-state-fg-danger)",
"syntax-diff-delete": "#fab283",
"syntax-diff-unknown": "#edb2f1",
"surface-critical-base": "#1F0603"
},
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.18.12",
"version": "1.18.11",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
+14 -10
View File
@@ -2244,9 +2244,9 @@ Some useful routing options:
### xAI
Three ways to authenticate: a SuperGrok subscription via device-code OAuth, the same SuperGrok subscription via a local callback, or a pay-as-you-go API key from the xAI console.
Three ways to authenticate: a SuperGrok subscription via browser OAuth, the same SuperGrok subscription via a headless device-code flow (for VPS / SSH / Docker), or a pay-as-you-go API key from the xAI console.
#### Option A — SuperGrok OAuth
#### Option A — SuperGrok OAuth (browser login)
1. Run the `/connect` command and search for **xAI**.
@@ -2254,11 +2254,9 @@ Three ways to authenticate: a SuperGrok subscription via device-code OAuth, the
/connect
```
2. Select **xAI Grok OAuth (SuperGrok Subscription)**. OpenCode prints a verification URL and a short user code.
2. Select **xAI Grok OAuth (SuperGrok Subscription)**. OpenCode opens xAI's consent screen in your browser and waits for the callback on `http://127.0.0.1:56121/callback`.
3. Open the URL, enter the code, and approve the consent screen. OpenCode polls xAI's token endpoint and stores the resulting OAuth tokens once you approve.
4. Run the `/models` command to select a Grok model.
3. Run the `/models` command to select a Grok model.
```txt
/models
@@ -2266,17 +2264,23 @@ Three ways to authenticate: a SuperGrok subscription via device-code OAuth, the
OpenCode refreshes the OAuth access token automatically. Any Grok or X Premium plan that includes Grok API access works; you do not need a separate `XAI_API_KEY`.
#### Option B — SuperGrok local callback
#### Option B — SuperGrok device-code (headless / remote server / VPS)
Use this only if you prefer a local browser callback and the browser can reach OpenCode on the same machine.
Use this when OpenCode is running somewhere a browser can't reach the loopback redirect: a VPS, a remote dev box over SSH, inside Docker, in CI, etc. No callback port is opened on the host running OpenCode — instead xAI hands the CLI a short code that you type into a browser on any other device (laptop, phone, …).
1. Run the `/connect` command and search for **xAI**.
1. Run the `/connect` command on the remote host and search for **xAI**.
```txt
/connect
```
2. Select **xAI Grok OAuth (Local Callback)**. OpenCode opens xAI's consent screen and waits for the callback on `http://127.0.0.1:56121/callback`. Token refresh works the same as Option A.
2. Select **xAI Grok OAuth (Headless / Remote / VPS)**. OpenCode prints a verification URL and a short user code.
```txt
Open https://x.ai/device on any device and enter code: ABCD-1234
```
3. Open the URL on a device that has a browser (your laptop or phone), enter the code, and approve the consent screen. OpenCode polls xAI's token endpoint and stores the resulting OAuth tokens once you approve. Token refresh works the same as Option A.
#### Option C — API key
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.18.12",
"version": "1.18.11",
"publisher": "sst-dev",
"repository": {
"type": "git",