Merge branch 'dev' of github.com:anomalyco/opencode into dev
This commit is contained in:
commit
e03db9bc69
43 changed files with 212 additions and 144 deletions
1
.github/TEAM_MEMBERS
vendored
1
.github/TEAM_MEMBERS
vendored
|
|
@ -20,3 +20,4 @@ Slickstef11
|
|||
usrnk1
|
||||
vimtor
|
||||
StarpTech
|
||||
vaprdev
|
||||
|
|
|
|||
56
bun.lock
56
bun.lock
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -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." } },
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/console-support",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ export const TuiThreadCommand = cmd({
|
|||
unguard?.()
|
||||
} catch {}
|
||||
}
|
||||
process.exit(0)
|
||||
process.exit()
|
||||
},
|
||||
})
|
||||
// scratch
|
||||
|
|
|
|||
|
|
@ -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 }))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/session-ui",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.30",
|
||||
"version": "1.18.31",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
|
|||
4
packages/ui/src/assets/icons/provider/merge-gateway.svg
Normal file
4
packages/ui/src/assets/icons/provider/merge-gateway.svg
Normal 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 |
|
|
@ -52,6 +52,7 @@ export const iconNames = [
|
|||
"minimax-coding-plan",
|
||||
"minimax-cn",
|
||||
"minimax-cn-coding-plan",
|
||||
"merge-gateway",
|
||||
"meganova",
|
||||
"lucidquery",
|
||||
"lmstudio",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue