Merge branch 'dev' of github.com:anomalyco/opencode into dev

This commit is contained in:
Frank 2026-09-14 17:41:36 -04:00
commit e03db9bc69
43 changed files with 212 additions and 144 deletions

View file

@ -20,3 +20,4 @@ Slickstef11
usrnk1
vimtor
StarpTech
vaprdev

View file

@ -29,7 +29,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@corvu/drawer": "catalog:",
"@dnd-kit/abstract": "0.5.0",
@ -96,7 +96,7 @@
},
"packages/cli": {
"name": "@opencode-ai/cli",
"version": "1.18.30",
"version": "1.18.31",
"bin": {
"lildax": "./bin/lildax.cjs",
},
@ -144,7 +144,7 @@
},
"packages/codemode": {
"name": "@opencode-ai/codemode",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"acorn": "8.15.0",
"effect": "catalog:",
@ -158,7 +158,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@ -195,7 +195,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@ -222,7 +222,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@ai-sdk/anthropic": "3.0.82",
"@ai-sdk/openai": "3.0.48",
@ -245,7 +245,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@ -269,7 +269,7 @@
},
"packages/console/support": {
"name": "@opencode-ai/console-support",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@opencode-ai/console-core": "workspace:*",
@ -289,7 +289,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.18.30",
"version": "1.18.31",
"bin": {
"opencode": "./bin/opencode",
},
@ -383,7 +383,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"drizzle-orm": "catalog:",
@ -437,7 +437,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@ -451,7 +451,7 @@
},
"packages/effect-sqlite-node": {
"name": "@opencode-ai/effect-sqlite-node",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"effect": "catalog:",
},
@ -463,7 +463,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@hono/standard-validator": "catalog:",
"@opencode-ai/core": "workspace:*",
@ -495,7 +495,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@ -511,7 +511,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@effect/platform-node": "4.0.0-beta.83",
"@effect/platform-node-shared": "4.0.0-beta.83",
@ -542,7 +542,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@opencode-ai/schema": "workspace:*",
"@smithy/eventstream-codec": "4.2.14",
@ -561,7 +561,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.18.30",
"version": "1.18.31",
"bin": {
"opencode": "./bin/opencode",
},
@ -692,7 +692,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@ai-sdk/provider": "3.0.8",
"@opencode-ai/sdk": "workspace:*",
@ -768,7 +768,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"cross-spawn": "catalog:",
},
@ -783,7 +783,7 @@
},
"packages/server": {
"name": "@opencode-ai/server",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/protocol": "workspace:*",
@ -798,7 +798,7 @@
},
"packages/session-ui": {
"name": "@opencode-ai/session-ui",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
@ -838,7 +838,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@ -851,7 +851,7 @@
},
"packages/stats/app": {
"name": "@opencode-ai/stats-app",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@ibm/plex": "6.4.1",
"@kobalte/core": "catalog:",
@ -878,7 +878,7 @@
},
"packages/stats/core": {
"name": "@opencode-ai/stats-core",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@aws-sdk/client-athena": "3.933.0",
"@planetscale/database": "1.19.0",
@ -897,7 +897,7 @@
},
"packages/stats/server": {
"name": "@opencode-ai/stats-server",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@aws-sdk/client-firehose": "3.933.0",
"@effect/platform-node": "catalog:",
@ -939,7 +939,7 @@
},
"packages/tui": {
"name": "@opencode-ai/tui",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
@ -966,7 +966,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@kobalte/core": "catalog:",
"@pierre/diffs": "catalog:",
@ -1017,7 +1017,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",

View file

@ -1,41 +0,0 @@
import { expect, test } from "@playwright/test"
import { base64Encode } from "@opencode-ai/core/util/encode"
import { mockOpenCodeServer } from "../utils/mock-server"
const draftID = "draft_legacy_new_session"
const directory = "C:/OpenCode/LegacyNewSession"
const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}`
test("redirects a draft to the legacy new-session route", async ({ page }) => {
await mockOpenCodeServer(page, {
directory,
project: {
id: "proj_legacy_new_session",
worktree: directory,
vcs: "git",
name: "legacy-new-session",
time: { created: 1700000000000, updated: 1700000000000 },
sandboxes: [],
},
provider: { all: [], connected: [], default: {} },
sessions: [],
pageMessages: () => ({ items: [] }),
})
await page.addInitScript(
({ directory, draftID, server }) => {
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: false } }))
localStorage.setItem("app-version.v1", JSON.stringify({ version: "1.17.20" }))
localStorage.setItem(
"opencode.window.browser.dat:tabs",
JSON.stringify([{ type: "draft", draftID, server, directory }]),
)
},
{ directory, draftID, server },
)
await page.goto(`/new-session?draftId=${draftID}`)
await expect(page).toHaveURL(`/${base64Encode(directory)}/session`)
await expect(page.locator("header[data-tauri-drag-region]")).toBeVisible()
await expect(page.locator('[data-component="prompt-input"]')).toBeVisible()
})

View file

@ -128,7 +128,7 @@ test.describe("session timeline projection", () => {
await expect(page.locator('[data-timeline-row="TurnGap"]')).toBeVisible()
})
test("renders comment strips and historical diff summary overflow", async ({ page }) => {
test("renders inline comments and historical diff summary overflow", async ({ page }) => {
const user = userMessage(
[
userText("The user made the following comment regarding lines 4 through 8 of src/a.ts: Keep this stable", {
@ -152,14 +152,10 @@ test.describe("session timeline projection", () => {
parentID: "msg_2000_diff_next_user",
created: 1700000011000,
})
await setupTimeline(page, {
messages: [user, assistantMessage(), nextUser, nextAssistant],
settings: { newLayoutDesigns: false },
})
await setupTimeline(page, { messages: [user, assistantMessage(), nextUser, nextAssistant] })
const scroller = page.locator(".scroll-view__viewport", { has: page.locator("[data-timeline-row]") })
await scroller.evaluate((element) => (element.scrollTop = 0))
await expect(page.locator('[data-timeline-row="CommentStrip"]')).toBeVisible()
await expect(page.getByText("Keep this stable", { exact: true })).toBeVisible()
await expect(page.locator('[data-timeline-row="DiffSummary"]')).toBeVisible()
await expect(page.getByText(/show all/i)).toBeVisible()

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.18.30",
"version": "1.18.31",
"description": "",
"type": "module",
"exports": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/cli",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"bin": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/codemode",
"version": "1.18.30",
"version": "1.18.31",
"description": "Effect-native confined code execution over schema-described tools",
"private": true,
"type": "module",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,5 +1,5 @@
import { Resource } from "@opencode-ai/console-resource"
import { and, Database, eq, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js"
import { and, Database, eq, isNotNull, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js"
import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js"
import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js"
import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
@ -34,7 +34,6 @@ export async function proxyInference(
: undefined)
if (!path) return undefined
const go = url.pathname.startsWith("/zen/go/")
const key = url.pathname.endsWith("/messages")
? request.headers.get("x-api-key")
: path.startsWith("/google/")
@ -42,44 +41,23 @@ export async function proxyInference(
: request.headers.get("authorization")?.split(" ")[1]
if (!key || key === "public") return undefined
// Routing only; the destination owns authentication and revocation after cutover.
const workspace = await Database.use((tx) =>
tx
.select({
id: WorkspaceTable.id,
migratedAt: WorkspaceTable.migrated_at,
provider: ProviderTable.provider,
})
.from(KeyTable)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
.leftJoin(
ProviderTable,
!go && generation?.provider
? and(
eq(ProviderTable.workspaceID, KeyTable.workspaceID),
eq(ProviderTable.provider, generation.provider),
isNull(ProviderTable.timeDeleted),
sql`length(${ProviderTable.credentials}) > 0`,
)
: sql`false`,
)
.where(eq(KeyTable.key, key))
.limit(1)
.then((rows) => rows[0]),
)
if (!workspace?.migratedAt) return undefined
const model = workspace.provider ? generation?.model : undefined
if (workspace.provider && !model) throw new Error("Legacy BYOK model mapping is unavailable")
// New Console keys are never in the legacy key table; every legacy key is `sk-`.
const legacy = !key.startsWith("oc_sk_")
const workspace = legacy ? await migratedWorkspace(key, generation?.provider) : undefined
if (legacy && !workspace) return undefined
const model = workspace?.provider ? generation?.model : undefined
if (workspace?.provider && !model) throw new Error("Legacy BYOK model mapping is unavailable")
const destination = new URL(Resource.ConsoleMigration.inferenceUrl)
// Imported connections must use this same workspace/provider-derived ID.
const target = model
? `/custom/conn_${workspace.id.slice(4)}_${workspace.provider}${
path.startsWith("/google/")
? `/models/${encodeURIComponent(model)}${url.pathname.slice(url.pathname.lastIndexOf(":"))}`
: url.pathname.slice("/zen/v1".length)
}`
: path
const target =
model && workspace
? `/custom/conn_${workspace.id.slice(4)}_${workspace.provider}${
path.startsWith("/google/")
? `/models/${encodeURIComponent(model)}${url.pathname.slice(url.pathname.lastIndexOf(":"))}`
: url.pathname.slice("/zen/v1".length)
}`
: path
destination.pathname = `${destination.pathname.replace(/\/$/, "")}${target}`
destination.search = url.search
destination.hash = ""
@ -109,6 +87,30 @@ export async function proxyInference(
return fetch(forwarded, { redirect: "manual" })
}
// Routing only; the destination owns authentication and revocation after cutover.
function migratedWorkspace(key: string, provider?: string) {
return Database.use((tx) =>
tx
.select({ id: WorkspaceTable.id, provider: ProviderTable.provider })
.from(KeyTable)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID))
.leftJoin(
ProviderTable,
provider
? and(
eq(ProviderTable.workspaceID, KeyTable.workspaceID),
eq(ProviderTable.provider, provider),
isNull(ProviderTable.timeDeleted),
sql`length(${ProviderTable.credentials}) > 0`,
)
: sql`false`,
)
.where(and(eq(KeyTable.key, key), isNotNull(WorkspaceTable.migrated_at)))
.limit(1)
.then((rows) => rows[0]),
)
}
export function inferenceUnavailable() {
return Response.json(
{ error: { type: "api_error", message: "Inference routing is unavailable. Please retry later." } },

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.18.30",
"version": "1.18.31",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.18.30",
"version": "1.18.31",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-support",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "@opencode-ai/effect-sqlite-node",
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.18.30",
"version": "1.18.31",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "@opencode-ai/http-recorder",
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
"type": "module",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.18.30",
"version": "1.18.31",
"name": "opencode",
"type": "module",
"license": "MIT",

View file

@ -303,7 +303,7 @@ export const TuiThreadCommand = cmd({
unguard?.()
} catch {}
}
process.exit(0)
process.exit()
},
})
// scratch

View file

@ -20,7 +20,8 @@ export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect)
ConfigErrorV1.JsonError.isInstance(error) ||
ConfigErrorV1.InvalidError.isInstance(error) ||
ConfigErrorV1.FrontmatterError.isInstance(error) ||
ConfigErrorV1.DirectoryTypoError.isInstance(error)
ConfigErrorV1.DirectoryTypoError.isInstance(error) ||
ConfigErrorV1.RemoteAuthError.isInstance(error)
) {
return Effect.succeed(HttpServerResponse.jsonUnsafe(error.toObject(), { status: 400 }))
}

View file

@ -83,6 +83,27 @@ describe("HttpApi error middleware", () => {
}),
)
it.live("returns remote auth defects as structured client errors", () =>
Effect.gen(function* () {
const configError = new ConfigErrorV1.RemoteAuthError({
url: "https://example.com",
remote: "https://config.example.com/opencode.json",
})
yield* HttpRouter.add("GET", "/remote-auth-error", Effect.die(configError)).pipe(
Layer.provide(errorLayer),
HttpRouter.serve,
Layer.build,
)
const response = yield* HttpClientRequest.get("/remote-auth-error").pipe(HttpClient.execute)
const body = yield* response.json
expect(response.status).toBe(400)
expect(body).toEqual(configError.toObject())
}),
)
it.live("does not map storage not-found defects to 404", () =>
Effect.gen(function* () {
yield* HttpRouter.add(

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/server",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/session-ui",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"scripts": {

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-app",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-core",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-server",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/tui",
"version": "1.18.30",
"version": "1.18.31",
"private": true,
"type": "module",
"license": "MIT",

View file

@ -356,8 +356,10 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
)
yield* Effect.sync(() => {
win32FlushInputBuffer()
if (result.reason !== undefined)
if (result.reason !== undefined) {
process.stderr.write((cliErrorMessage(result.reason) ?? errorFormat(result.reason)) + "\n")
process.exitCode = 1
}
if (result.epilogue) process.stdout.write(result.epilogue + "\n")
})
})

View file

@ -47,6 +47,17 @@ export function cliErrorMessage(input: unknown): string | undefined {
const frontmatter = configData(input, "ConfigFrontmatterError")
if (frontmatter) return field(frontmatter, "message") ?? ""
const remoteAuth = configData(input, "ConfigRemoteAuthError")
if (remoteAuth) {
const url = field(remoteAuth, "url")
const remote = field(remoteAuth, "remote")
return [
`Failed to load remote config${remote ? ` from ${remote}` : ""}: the server returned a login page instead of JSON.`,
"Authentication is missing or has expired (the endpoint is likely behind an SSO or identity-aware proxy).",
...(url ? [`Run \`opencode auth login ${url}\` to re-authenticate.`] : []),
].join("\n")
}
const invalid = configData(input, "ConfigInvalidError")
if (invalid) {
const path = field(invalid, "path")

View file

@ -126,3 +126,65 @@ test("app.exit prints the session epilogue after scoped cleanup", async () => {
mock.restore()
}
})
test("fatal startup errors set a nonzero exit after scoped cleanup", async () => {
const setup = await createTestRenderer({ width: 80, height: 24, useThread: false })
const core = await import("@opentui/core")
await mock.module("@opentui/core", () => ({ ...core, createCliRenderer: async () => setup.renderer }))
const events = createEventSource()
const calls = createFetch((url) => {
if (url.pathname === "/config")
return json(
{
name: "ConfigRemoteAuthError",
data: {
url: "https://example.com",
remote: "https://config.example.com/opencode.json",
},
},
{ status: 400 },
)
return undefined
})
let disposes = 0
const originalWrite = process.stderr.write.bind(process.stderr)
const originalExitCode = process.exitCode ?? 0
let stderr = ""
process.stderr.write = ((chunk: string | Uint8Array) => {
stderr += String(chunk)
return true
}) as typeof process.stderr.write
try {
const { run } = await import("../src/app")
const task = Effect.runPromise(
run({
url: "http://test",
directory,
config: createTuiResolvedConfig({ plugin_enabled: {} }),
fetch: calls.fetch,
events: events.source,
args: {},
pluginHost: {
async start() {},
async dispose() {
disposes++
},
},
}).pipe(Effect.provide(AppNodeBuilder.build(Global.node))),
)
await task
expect(stderr).toContain("Run `opencode auth login https://example.com` to re-authenticate.")
expect(stderr).not.toContain("Unexpected server error")
expect(process.exitCode).toBe(1)
expect(setup.renderer.isDestroyed).toBe(true)
expect(disposes).toBe(1)
} finally {
process.stderr.write = originalWrite
process.exitCode = originalExitCode
if (!setup.renderer.isDestroyed) setup.renderer.destroy()
mock.restore()
}
})

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.18.30",
"version": "1.18.31",
"type": "module",
"license": "MIT",
"repository": {

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 972.39 1200" fill="currentColor">
<path d="M710.81,430.08c-113.18,26.23-221.41,69.47-320.66,127.37C229,455.13,95.02,310.75,5.46,135.65c-12.29-24.1-2.36-53.88,22.45-64.98L173.71,4.27c22.68-10.4,49.62-1.18,61.2,20.79,101.14,193.76,273.4,337.67,475.9,405.02Z"/>
<path d="M173.7,1195.69l-146.03-66.4c-24.58-11.34-34.74-40.88-22.45-64.98C182.45,718.13,534.06,491.76,922.53,473.8c27.18-1.18,49.86,20.32,49.86,47.26v160.44c0,25.05-19.38,45.61-44.43,47.02-292.77,15.59-557.66,186.2-693.3,446.37-11.58,22.21-38.52,31.19-61.2,20.79h.24Z"/>
</svg>

After

Width:  |  Height:  |  Size: 594 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 276 KiB

View file

@ -52,6 +52,7 @@ export const iconNames = [
"minimax-coding-plan",
"minimax-cn",
"minimax-cn-coding-plan",
"merge-gateway",
"meganova",
"lucidquery",
"lmstudio",

View file

@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.18.30",
"version": "1.18.31",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",

View file

@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.18.30",
"version": "1.18.31",
"publisher": "sst-dev",
"repository": {
"type": "git",