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

This commit is contained in:
David Hill 2025-12-11 10:47:24 +00:00
commit e91d121ef8
95 changed files with 520 additions and 335 deletions

View file

@ -29,5 +29,6 @@ jobs:
uses: sst/opencode/github@latest
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
OPENCODE_PERMISSION: '{"bash": "deny"}'
with:
model: opencode/claude-haiku-4-5

View file

@ -55,7 +55,7 @@ jobs:
- name: Install OpenCode
if: inputs.bump || inputs.version
run: curl -fsSL https://opencode.ai/install | bash
run: bun i -g opencode-ai@1.0.143
- name: Login to GitHub Container Registry
uses: docker/login-action@v3

View file

@ -1,6 +1,6 @@
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-openai-codex-auth"],
// "plugin": ["opencode-openai-codex-auth"],
// "enterprise": {
// "url": "https://enterprise.dev.opencode.ai",
// },
@ -10,17 +10,4 @@
"options": {},
},
},
"mcp": {
"exa": {
"type": "remote",
"url": "https://mcp.exa.ai/mcp",
},
"morph": {
"type": "local",
"command": ["bunx", "@morphllm/morphmcp"],
"environment": {
"ENABLED_TOOLS": "warp_grep",
},
},
},
}

View file

@ -20,7 +20,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@ -48,7 +48,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@ -75,7 +75,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@ -99,7 +99,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@ -123,7 +123,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@ -168,7 +168,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@ -179,6 +179,7 @@
"aws4fetch": "^1.0.20",
"hono": "catalog:",
"hono-openapi": "catalog:",
"js-base64": "3.7.7",
"luxon": "catalog:",
"nitro": "3.0.1-alpha.1",
"solid-js": "catalog:",
@ -196,7 +197,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "22.0.0",
@ -212,7 +213,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.0.143",
"version": "1.0.146",
"bin": {
"opencode": "./bin/opencode",
},
@ -304,7 +305,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@ -324,7 +325,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.0.143",
"version": "1.0.146",
"devDependencies": {
"@hey-api/openapi-ts": "0.88.1",
"@tsconfig/node22": "catalog:",
@ -335,7 +336,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@ -348,7 +349,7 @@
},
"packages/tauri": {
"name": "@opencode-ai/tauri",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@opencode-ai/desktop": "workspace:*",
"@tauri-apps/api": "^2",
@ -370,7 +371,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@ -402,7 +403,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"zod": "catalog:",
},
@ -413,7 +414,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.0.143",
"version": "1.0.146",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",

View file

@ -1,10 +1,10 @@
import { SECRET } from "./secret"
import { domain } from "./stage"
import { domain, shortDomain } from "./stage"
const storage = new sst.cloudflare.Bucket("EnterpriseStorage")
const enterprise = new sst.cloudflare.x.SolidStart("Enterprise", {
domain: "enterprise." + domain,
const teams = new sst.cloudflare.x.SolidStart("Teams", {
domain: shortDomain,
path: "packages/enterprise",
buildCommand: "bun run build:cloudflare",
environment: {

View file

@ -11,3 +11,9 @@ new cloudflare.RegionalHostname("RegionalHostname", {
regionKey: "us",
zoneId: zoneID,
})
export const shortDomain = (() => {
if ($app.stage === "production") return "opncd.ai"
if ($app.stage === "dev") return "dev.opncd.ai"
return `${$app.stage}.dev.opncd.ai`
})()

View file

@ -1,3 +1,3 @@
{
"nodeModules": "sha256-WQMQmqKojxdRtwv6KL9HBaDfwYa4qPn2pvXKqgNM73A="
"nodeModules": "sha256-WcFRAG8w1XwgZxzyAawkQ7mYfJxu5VhA3sPApEG6FdI="
}

View file

@ -4,7 +4,7 @@
"description": "AI-powered development tool",
"private": true,
"type": "module",
"packageManager": "bun@1.3.4",
"packageManager": "bun@1.3.3",
"scripts": {
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
"typecheck": "bun turbo typecheck",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",

View file

@ -0,0 +1,20 @@
import type { APIEvent } from "@solidjs/start/server"
async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}`
const response = await fetch(targetUrl, {
method: req.method,
headers: req.headers,
body: req.body,
})
return response
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const DELETE = handler
export const OPTIONS = handler
export const PATCH = handler

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
"version": "1.0.143",
"version": "1.0.146",
"description": "",
"type": "module",
"exports": {

View file

@ -14,11 +14,11 @@
"strict": true,
"noEmit": false,
"emitDeclarationOnly": true,
"outDir": "ts-dist",
"outDir": "node_modules/.ts-dist",
"isolatedModules": true,
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["dist"]
"exclude": ["dist", "ts-dist"]
}

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.0.143",
"version": "1.0.146",
"private": true,
"type": "module",
"scripts": {
@ -20,6 +20,7 @@
"@solidjs/meta": "catalog:",
"hono": "catalog:",
"hono-openapi": "catalog:",
"js-base64": "3.7.7",
"luxon": "catalog:",
"nitro": "3.0.1-alpha.1",
"solid-js": "catalog:",

View file

@ -11,8 +11,6 @@ export default createHandler(() => (
<title>OpenCode</title>
<meta name="theme-color" content="#F8F7F7" />
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
{assets}
</head>
<body class="antialiased overscroll-none select-none text-12-regular">

View file

@ -0,0 +1,3 @@
export default function () {
return <div>Hello World</div>
}

View file

@ -23,6 +23,8 @@ import { preloadMultiFileDiff, PreloadMultiFileDiffResult } from "@pierre/precis
import { Diff as SSRDiff } from "@opencode-ai/ui/diff-ssr"
import { clientOnly } from "@solidjs/start"
import { type IconName } from "@opencode-ai/ui/icons/provider"
import { Meta } from "@solidjs/meta"
import { Base64 } from "js-base64"
const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff })))
@ -41,6 +43,7 @@ const getData = query(async (shareID) => {
const data = await Share.data(shareID)
const result: {
sessionID: string
shareID: string
session: Session[]
session_diff: {
[sessionID: string]: FileDiff[]
@ -65,6 +68,7 @@ const getData = query(async (shareID) => {
}
} = {
sessionID: share.sessionID,
shareID,
session: [],
session_diff: {
[share.sessionID]: [],
@ -153,244 +157,277 @@ export default function () {
)
}}
>
<Meta name="robots" content="noindex, nofollow" />
<Show when={data()}>
{(data) => {
const match = createMemo(() => Binary.search(data().session, data().sessionID, (s) => s.id))
if (!match().found) throw new Error(`Session ${data().sessionID} not found`)
const info = createMemo(() => data().session[match().index])
const ogImage = createMemo(() => {
const models = new Set<string>()
const messages = data().message[data().sessionID] ?? []
for (const msg of messages) {
if (msg.role === "assistant" && msg.modelID) {
models.add(msg.modelID)
}
}
const modelIDs = Array.from(models)
const encodedTitle = encodeURIComponent(Base64.encode(encodeURIComponent(info().title.substring(0, 700))))
let modelParam: string
if (modelIDs.length === 1) {
modelParam = modelIDs[0]
} else if (modelIDs.length === 2) {
modelParam = encodeURIComponent(`${modelIDs[0]} & ${modelIDs[1]}`)
} else if (modelIDs.length > 2) {
modelParam = encodeURIComponent(`${modelIDs[0]} & ${modelIDs.length - 1} others`)
} else {
modelParam = "unknown"
}
const version = `v${info().version}`
return `https://social-cards.sst.dev/opencode-share/${encodedTitle}.png?model=${modelParam}&version=${version}&id=${data().shareID}`
})
return (
<DiffComponentProvider component={ClientOnlyDiff}>
<DataProvider data={data()} directory={info().directory}>
{iife(() => {
const [store, setStore] = createStore({
messageId: undefined as string | undefined,
})
const messages = createMemo(() =>
data().sessionID
? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort(
(a, b) => b.time.created - a.time.created,
)
: [],
)
const firstUserMessage = createMemo(() => messages().at(0))
const activeMessage = createMemo(
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
)
function setActiveMessage(message: UserMessage | undefined) {
if (message) {
setStore("messageId", message.id)
} else {
setStore("messageId", undefined)
<>
<Meta name="description" content="opencode - The AI coding agent built for the terminal." />
<Meta property="og:image" content={ogImage()} />
<Meta name="twitter:image" content={ogImage()} />
<DiffComponentProvider component={ClientOnlyDiff}>
<DataProvider data={data()} directory={info().directory}>
{iife(() => {
const [store, setStore] = createStore({
messageId: undefined as string | undefined,
})
const messages = createMemo(() =>
data().sessionID
? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort(
(a, b) => b.time.created - a.time.created,
)
: [],
)
const firstUserMessage = createMemo(() => messages().at(0))
const activeMessage = createMemo(
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
)
function setActiveMessage(message: UserMessage | undefined) {
if (message) {
setStore("messageId", message.id)
} else {
setStore("messageId", undefined)
}
}
}
const provider = createMemo(() => activeMessage()?.model?.providerID)
const modelID = createMemo(() => activeMessage()?.model?.modelID)
const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID()))
const diffs = createMemo(() => {
const diffs = data().session_diff[data().sessionID] ?? []
const preloaded = data().session_diff_preload[data().sessionID] ?? []
return diffs.map((diff) => ({
...diff,
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
}))
})
const splitDiffs = createMemo(() => {
const diffs = data().session_diff[data().sessionID] ?? []
const preloaded = data().session_diff_preload_split[data().sessionID] ?? []
return diffs.map((diff) => ({
...diff,
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
}))
})
const provider = createMemo(() => activeMessage()?.model?.providerID)
const modelID = createMemo(() => activeMessage()?.model?.modelID)
const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID()))
const diffs = createMemo(() => {
const diffs = data().session_diff[data().sessionID] ?? []
const preloaded = data().session_diff_preload[data().sessionID] ?? []
return diffs.map((diff) => ({
...diff,
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
}))
})
const splitDiffs = createMemo(() => {
const diffs = data().session_diff[data().sessionID] ?? []
const preloaded = data().session_diff_preload_split[data().sessionID] ?? []
return diffs.map((diff) => ({
...diff,
preloaded: preloaded.find((d) => d.newFile.name === diff.file),
}))
})
const title = () => (
<div class="flex flex-col gap-4">
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
<Mark class="shrink-0 w-3 my-0.5" />
<div class="text-12-mono text-text-base">v{info().version}</div>
const title = () => (
<div class="flex flex-col gap-4">
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
<Mark class="shrink-0 w-3 my-0.5" />
<div class="text-12-mono text-text-base">v{info().version}</div>
</div>
<div class="flex gap-2 items-center">
<ProviderIcon id={provider() as IconName} class="size-3.5 shrink-0 text-icon-strong-base" />
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
</div>
<div class="text-12-regular text-text-weaker">
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
</div>
</div>
<div class="flex gap-2 items-center">
<ProviderIcon id={provider() as IconName} class="size-3.5 shrink-0 text-icon-strong-base" />
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
</div>
)
const turns = () => (
<div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar">
<div class="px-4">{title()}</div>
<div class="flex flex-col gap-15 items-start justify-start mt-4">
<For each={messages()}>
{(message) => (
<SessionTurn
sessionID={data().sessionID}
messageID={message.id}
classes={{
root: "min-w-0 w-full relative",
content:
"flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]",
container: "px-4",
}}
/>
)}
</For>
</div>
<div class="text-12-regular text-text-weaker">
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
<div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0">
<Logo class="w-58.5 opacity-12" />
</div>
</div>
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
</div>
)
)
const turns = () => (
<div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar">
<div class="px-4">{title()}</div>
<div class="flex flex-col gap-15 items-start justify-start mt-4">
<For each={messages()}>
{(message) => (
<SessionTurn
sessionID={data().sessionID}
messageID={message.id}
classes={{
root: "min-w-0 w-full relative",
content:
"flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]",
container: "px-4",
}}
const wide = createMemo(() => diffs().length === 0)
return (
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
<div class="">
<a href="https://opencode.ai">
<Mark />
</a>
</div>
<div class="flex gap-3 items-center">
<IconButton
as={"a"}
href="https://github.com/sst/opencode"
target="_blank"
icon="github"
variant="ghost"
/>
)}
</For>
</div>
<div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0">
<Logo class="w-58.5 opacity-12" />
</div>
</div>
)
const wide = createMemo(() => diffs().length === 0)
return (
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
<div class="">
<a href="https://opencode.ai">
<Mark />
</a>
</div>
<div class="flex gap-3 items-center">
<IconButton
as={"a"}
href="https://github.com/sst/opencode"
target="_blank"
icon="github"
variant="ghost"
/>
<IconButton
as={"a"}
href="https://opencode.ai/discord"
target="_blank"
icon="discord"
variant="ghost"
/>
</div>
</header>
<div class="select-text flex flex-col flex-1 min-h-0">
<div
classList={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}
>
<IconButton
as={"a"}
href="https://opencode.ai/discord"
target="_blank"
icon="discord"
variant="ghost"
/>
</div>
</header>
<div class="select-text flex flex-col flex-1 min-h-0">
<div
classList={{
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true,
"mx-auto max-w-146": !wide(),
}}
classList={{ "hidden w-full flex-1 min-h-0": true, "md:flex": wide(), "lg:flex": !wide() }}
>
<div
classList={{
"w-full flex justify-start items-start min-w-0": true,
"max-w-146 mx-auto px-6": wide(),
"pr-6 pl-18": !wide() && messages().length > 1,
"px-6": !wide() && messages().length === 1,
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true,
"mx-auto max-w-146": !wide(),
}}
>
{title()}
</div>
<div class="flex items-start justify-start h-full min-h-0">
<SessionMessageRail
messages={messages()}
current={activeMessage()}
onMessageSelect={setActiveMessage}
wide={wide()}
/>
<SessionTurn
sessionID={data().sessionID}
messageID={store.messageId ?? firstUserMessage()!.id!}
classes={{
root: "grow",
content: "flex flex-col justify-between items-start",
container:
"w-full pb-20 " +
(wide() ? "max-w-146 mx-auto px-6" : messages().length > 1 ? "pr-6 pl-18" : "px-6"),
<div
classList={{
"w-full flex justify-start items-start min-w-0": true,
"max-w-146 mx-auto px-6": wide(),
"pr-6 pl-18": !wide() && messages().length > 1,
"px-6": !wide() && messages().length === 1,
}}
>
<div classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }}>
<Logo class="w-58.5 opacity-12" />
</div>
</SessionTurn>
</div>
</div>
<Show when={diffs().length > 0}>
<DiffComponentProvider component={SSRDiff}>
<div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview
class="@4xl:hidden"
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
/>
<SessionReview
split
class="hidden @4xl:flex"
diffs={splitDiffs()}
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
/>
{title()}
</div>
<div class="flex items-start justify-start h-full min-h-0">
<SessionMessageRail
messages={messages()}
current={activeMessage()}
onMessageSelect={setActiveMessage}
wide={wide()}
/>
<SessionTurn
sessionID={data().sessionID}
messageID={store.messageId ?? firstUserMessage()!.id!}
classes={{
root: "grow",
content: "flex flex-col justify-between items-start",
container:
"w-full pb-20 " +
(wide()
? "max-w-146 mx-auto px-6"
: messages().length > 1
? "pr-6 pl-18"
: "px-6"),
}}
>
<div classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }}>
<Logo class="w-58.5 opacity-12" />
</div>
</SessionTurn>
</div>
</DiffComponentProvider>
</Show>
</div>
<Switch>
<Match when={diffs().length > 0}>
<Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}>
<Tabs.List>
<Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}>
Session
</Tabs.Trigger>
<Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}>
{diffs().length} Files Changed
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="session" class="!overflow-hidden">
{turns()}
</Tabs.Content>
<Tabs.Content
forceMount
value="review"
class="!overflow-hidden hidden data-[selected]:block"
>
<div class="relative h-full pt-8 overflow-y-auto no-scrollbar">
<DiffComponentProvider component={SSRDiff}>
<SessionReview
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-4",
container: "px-4",
}}
/>
</DiffComponentProvider>
</div>
</Tabs.Content>
</Tabs>
</Match>
<Match when={true}>
<div classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }}>
{turns()}
</div>
</Match>
</Switch>
<Show when={diffs().length > 0}>
<DiffComponentProvider component={SSRDiff}>
<div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview
class="@4xl:hidden"
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
/>
<SessionReview
split
class="hidden @4xl:flex"
diffs={splitDiffs()}
classes={{
root: "pb-20",
header: "px-6",
container: "px-6",
}}
/>
</div>
</DiffComponentProvider>
</Show>
</div>
<Switch>
<Match when={diffs().length > 0}>
<Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}>
<Tabs.List>
<Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}>
Session
</Tabs.Trigger>
<Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}>
{diffs().length} Files Changed
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="session" class="!overflow-hidden">
{turns()}
</Tabs.Content>
<Tabs.Content
forceMount
value="review"
class="!overflow-hidden hidden data-[selected]:block"
>
<div class="relative h-full pt-8 overflow-y-auto no-scrollbar">
<DiffComponentProvider component={SSRDiff}>
<SessionReview
diffs={diffs()}
classes={{
root: "pb-20",
header: "px-4",
container: "px-4",
}}
/>
</DiffComponentProvider>
</div>
</Tabs.Content>
</Tabs>
</Match>
<Match when={true}>
<div classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }}>
{turns()}
</div>
</Match>
</Switch>
</div>
</div>
</div>
)
})}
</DataProvider>
</DiffComponentProvider>
)
})}
</DataProvider>
</DiffComponentProvider>
</>
)
}}
</Show>

View file

@ -18,7 +18,14 @@ const nitroConfig: any = (() => {
})()
export default defineConfig({
plugins: [tailwindcss(), solidStart() as PluginOption, nitro(nitroConfig)],
plugins: [
tailwindcss(),
solidStart() as PluginOption,
nitro({
...nitroConfig,
baseURL: process.env.OPENCODE_BASE_URL,
}),
],
server: {
host: "0.0.0.0",
allowedHosts: true,

View file

@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.0.143"
version = "1.0.146"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/sst/opencode"
@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.143/opencode-darwin-arm64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.146/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.143/opencode-darwin-x64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.146/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.143/opencode-linux-arm64.tar.gz"
archive = "https://github.com/sst/opencode/releases/download/v1.0.146/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.143/opencode-linux-x64.tar.gz"
archive = "https://github.com/sst/opencode/releases/download/v1.0.146/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/sst/opencode/releases/download/v1.0.143/opencode-windows-x64.zip"
archive = "https://github.com/sst/opencode/releases/download/v1.0.146/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.0.143",
"version": "1.0.146",
"$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.0.143",
"version": "1.0.146",
"name": "opencode",
"type": "module",
"private": true,

View file

@ -7,7 +7,13 @@ import { GlobalBus } from "./global"
export namespace Bus {
const log = Log.create({ service: "bus" })
type Subscription = (event: any) => void
const disposedEventType = "server.instance.disposed"
export const InstanceDisposed = BusEvent.define(
"server.instance.disposed",
z.object({
directory: z.string(),
}),
)
const state = Instance.state(
() => {
@ -21,7 +27,7 @@ export namespace Bus {
const wildcard = entry.subscriptions.get("*")
if (!wildcard) return
const event = {
type: disposedEventType,
type: InstanceDisposed.type,
properties: {
directory: Instance.directory,
},
@ -32,13 +38,6 @@ export namespace Bus {
},
)
export const InstanceDisposed = BusEvent.define(
disposedEventType,
z.object({
directory: z.string(),
}),
)
export async function publish<Definition extends BusEvent.Definition>(
def: Definition,
properties: z.output<Definition["properties"]>,

View file

@ -894,7 +894,7 @@ export function Session() {
<box marginTop={1}>
<For each={revert()!.diffFiles}>
{(file) => (
<text>
<text fg={theme.text}>
{file.filename}
<Show when={file.additions > 0}>
<span style={{ fg: theme.diffAdded }}> +{file.additions}</span>

View file

@ -3,6 +3,7 @@ import { Context } from "../util/context"
import { Project } from "./project"
import { State } from "./state"
import { iife } from "@/util/iife"
import { GlobalBus } from "@/bus/global"
interface Context {
directory: string
@ -52,6 +53,15 @@ export const Instance = {
Log.Default.info("disposing instance", { directory: Instance.directory })
await State.dispose(Instance.directory)
cache.delete(Instance.directory)
GlobalBus.emit("event", {
directory: Instance.directory,
payload: {
type: "server.instance.disposed",
properties: {
directory: Instance.directory,
},
},
})
},
async disposeAll() {
Log.Default.info("disposing all instances")

View file

@ -318,6 +318,16 @@ export namespace Provider {
},
}
},
cerebras: async () => {
return {
autoload: false,
options: {
headers: {
"X-Cerebras-3rd-Party-Integration": "opencode",
},
},
}
},
}
export const Model = z

View file

@ -74,12 +74,17 @@ export namespace ProviderTransform {
return result
}
// TODO: rm later
const bugged =
(model.id === "kimi-k2-thinking" && model.providerID === "opencode") ||
(model.id === "moonshotai/Kimi-K2-Thinking" && model.providerID === "baseten")
if (
model.providerID === "deepseek" ||
model.api.id.toLowerCase().includes("deepseek") ||
(model.capabilities.interleaved &&
typeof model.capabilities.interleaved === "object" &&
model.capabilities.interleaved.field === "reasoning_content")
model.capabilities.interleaved.field === "reasoning_content" &&
!bugged)
) {
return msgs.map((msg) => {
if (msg.role === "assistant" && Array.isArray(msg.content)) {
@ -231,9 +236,11 @@ export namespace ProviderTransform {
if (model.api.npm === "@ai-sdk/google" || model.api.npm === "@ai-sdk/google-vertex") {
result["thinkingConfig"] = {
thinkingLevel: "high",
includeThoughts: true,
}
if (model.api.id.includes("gemini-3")) {
result["thinkingConfig"]["thinkingLevel"] = "high"
}
}
if (model.api.id.includes("gpt-5") && !model.api.id.includes("gpt-5-chat")) {

View file

@ -56,6 +56,7 @@ export namespace Server {
export const Event = {
Connected: BusEvent.define("server.connected", z.object({})),
Disposed: BusEvent.define("global.disposed", z.object({})),
}
const app = new Hono()
@ -140,6 +141,35 @@ export namespace Server {
})
},
)
.post(
"/global/dispose",
describeRoute({
summary: "Dispose instance",
description: "Clean up and dispose all OpenCode instances, releasing all resources.",
operationId: "global.dispose",
responses: {
200: {
description: "Global disposed",
content: {
"application/json": {
schema: resolver(z.boolean()),
},
},
},
},
}),
async (c) => {
await Instance.disposeAll()
GlobalBus.emit("event", {
directory: "global",
payload: {
type: Event.Disposed.type,
properties: {},
},
})
return c.json(true)
},
)
.use(async (c, next) => {
const directory = c.req.query("directory") ?? c.req.header("x-opencode-directory") ?? process.cwd()
return Instance.provide({

View file

@ -223,34 +223,13 @@ export namespace Session {
if (cfg.share === "disabled") {
throw new Error("Sharing is disabled in configuration")
}
if (cfg.enterprise?.url) {
const { ShareNext } = await import("@/share/share-next")
const share = await ShareNext.create(id)
await update(id, (draft) => {
draft.share = {
url: share.url,
}
})
}
const session = await get(id)
if (session.share) return session.share
const { Share } = await import("../share/share")
const share = await Share.create(id)
const { ShareNext } = await import("@/share/share-next")
const share = await ShareNext.create(id)
await update(id, (draft) => {
draft.share = {
url: share.url,
}
})
await Storage.write(["share", id], share)
await Share.sync("session/info/" + id, session)
for (const msg of await messages({ sessionID: id })) {
await Share.sync("session/message/" + id + "/" + msg.info.id, msg.info)
for (const part of msg.parts) {
await Share.sync("session/part/" + id + "/" + msg.info.id + "/" + part.id, part)
}
}
return share
})

View file

@ -11,9 +11,11 @@ import type * as SDK from "@opencode-ai/sdk/v2"
export namespace ShareNext {
const log = Log.create({ service: "share-next" })
async function url() {
return Config.get().then((x) => x.enterprise?.url ?? "https://opncd.ai")
}
export async function init() {
const config = await Config.get()
if (!config.enterprise) return
Bus.subscribe(Session.Event.Updated, async (evt) => {
await sync(evt.properties.info.id, [
{
@ -62,8 +64,7 @@ export namespace ShareNext {
export async function create(sessionID: string) {
log.info("creating share", { sessionID })
const url = await Config.get().then((x) => x.enterprise!.url)
const result = await fetch(`${url}/api/share`, {
const result = await fetch(`${await url()}/api/share`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -126,11 +127,10 @@ export namespace ShareNext {
const queued = queue.get(sessionID)
if (!queued) return
queue.delete(sessionID)
const url = await Config.get().then((x) => x.enterprise!.url)
const share = await get(sessionID)
if (!share) return
await fetch(`${url}/api/share/${share.id}/sync`, {
await fetch(`${await url()}/api/share/${share.id}/sync`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -146,10 +146,9 @@ export namespace ShareNext {
export async function remove(sessionID: string) {
log.info("removing share", { sessionID })
const url = await Config.get().then((x) => x.enterprise!.url)
const share = await get(sessionID)
if (!share) return
await fetch(`${url}/api/share/${share.id}`, {
await fetch(`${await url()}/api/share/${share.id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",

View file

@ -20,8 +20,7 @@ Usage notes:
- The command argument is required.
- You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes).
If not specified, commands will timeout after 120000ms (2 minutes).
- It is very helpful if you write a clear, concise description of what this command
does in 5-10 words.
- The description argument is required. You must write a clear, concise description of what this command does in 5-10 words.
- If the output exceeds 30000 characters, output will be truncated before being
returned to you.
- You can use the `run_in_background` parameter to run the command in the background,

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",

View file

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",

View file

@ -28,6 +28,7 @@ import type {
FindSymbolsResponses,
FindTextResponses,
FormatterStatusResponses,
GlobalDisposeResponses,
GlobalEventResponses,
InstanceDisposeResponses,
LspStatusResponses,
@ -193,6 +194,18 @@ export class Global extends HeyApiClient {
...options,
})
}
/**
* Dispose instance
*
* Clean up and dispose all OpenCode instances, releasing all resources.
*/
public dispose<ThrowOnError extends boolean = false>(options?: Options<never, ThrowOnError>) {
return (options?.client ?? this.client).post<GlobalDisposeResponses, unknown, ThrowOnError>({
url: "/global/dispose",
...options,
})
}
}
export class Project extends HeyApiClient {

View file

@ -725,6 +725,13 @@ export type EventServerConnected = {
}
}
export type EventGlobalDisposed = {
type: "global.disposed"
properties: {
[key: string]: unknown
}
}
export type Event =
| EventInstallationUpdated
| EventInstallationUpdateAvailable
@ -759,6 +766,7 @@ export type Event =
| EventPtyExited
| EventPtyDeleted
| EventServerConnected
| EventGlobalDisposed
export type GlobalEvent = {
directory: string
@ -1700,6 +1708,22 @@ export type GlobalEventResponses = {
export type GlobalEventResponse = GlobalEventResponses[keyof GlobalEventResponses]
export type GlobalDisposeData = {
body?: never
path?: never
query?: never
url: "/global/dispose"
}
export type GlobalDisposeResponses = {
/**
* Global disposed
*/
200: boolean
}
export type GlobalDisposeResponse = GlobalDisposeResponses[keyof GlobalDisposeResponses]
export type ProjectListData = {
body?: never
path?: never

View file

@ -31,6 +31,31 @@
]
}
},
"/global/dispose": {
"post": {
"operationId": "global.dispose",
"summary": "Dispose instance",
"description": "Clean up and dispose all OpenCode instances, releasing all resources.",
"responses": {
"200": {
"description": "Global disposed",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"x-codeSamples": [
{
"lang": "js",
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.dispose({\n ...\n})"
}
]
}
},
"/project": {
"get": {
"operationId": "project.list",
@ -6810,6 +6835,20 @@
},
"required": ["type", "properties"]
},
"Event.global.disposed": {
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "global.disposed"
},
"properties": {
"type": "object",
"properties": {}
}
},
"required": ["type", "properties"]
},
"Event": {
"anyOf": [
{
@ -6910,6 +6949,9 @@
},
{
"$ref": "#/components/schemas/Event.server.connected"
},
{
"$ref": "#/components/schemas/Event.global.disposed"
}
]
},

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"scripts": {
"dev": "bun run src/index.ts",

View file

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/tauri",
"private": true,
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"scripts": {
"typecheck": "tsgo -b",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 793 B

After

Width:  |  Height:  |  Size: 8.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 6.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 B

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 3.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,022 B

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 944 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 891 B

After

Width:  |  Height:  |  Size: 6.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 728 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

After

Width:  |  Height:  |  Size: 7.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 666 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

After

Width:  |  Height:  |  Size: 7.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 B

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,016 B

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

@ -1,7 +1,19 @@
{
"extends": "../desktop/tsconfig.json",
"compilerOptions": {
"outDir": "ts-dist"
"target": "ESNext",
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"allowJs": true,
"strict": true,
"isolatedModules": true,
"noEmit": true,
"emitDeclarationOnly": false,
"outDir": "node_modules/.ts-dist"
},
"references": [{ "path": "../desktop" }],
"include": ["src"]

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.0.143",
"version": "1.0.146",
"type": "module",
"exports": {
"./*": "./src/components/*.tsx",

View file

@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
"version": "1.0.143",
"version": "1.0.146",
"private": true,
"type": "module",
"exports": {

View file

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/web",
"type": "module",
"version": "1.0.143",
"version": "1.0.146",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",

View file

@ -37,13 +37,13 @@ This starts both a server and a client
#### Options
| Option | Type | Description | Default |
| --------------- | ---------- | -------------------------------- | ----------------------- |
| `baseUrl` | `string` | URL of the server | `http://localhost:4096` |
| `fetch` | `function` | Custom fetch implementation | `globalThis.fetch` |
| `parseAs` | `string` | Response parsing method | `auto` |
| `responseStyle` | `string` | Return style: `data` or `fields` | `fields` |
| `throwOnError` | `boolean` | Throw errors instead of return | `false` |
| Option | Type | Description | Default |
| ---------- | ------------- | ------------------------------ | ----------- |
| `hostname` | `string` | Server hostname | `127.0.0.1` |
| `port` | `number` | Server port | `4096` |
| `signal` | `AbortSignal` | Abort signal for cancellation | `undefined` |
| `timeout` | `number` | Timeout in ms for server start | `5000` |
| `config` | `Config` | Configuration object | `{}` |
---
@ -81,13 +81,13 @@ const client = createOpencodeClient({
#### Options
| Option | Type | Description | Default |
| ---------- | ------------- | ------------------------------ | ----------- |
| `hostname` | `string` | Server hostname | `127.0.0.1` |
| `port` | `number` | Server port | `4096` |
| `signal` | `AbortSignal` | Abort signal for cancellation | `undefined` |
| `timeout` | `number` | Timeout in ms for server start | `5000` |
| `config` | `Config` | Configuration object | `{}` |
| Option | Type | Description | Default |
| --------------- | ---------- | -------------------------------- | ----------------------- |
| `baseUrl` | `string` | URL of the server | `http://localhost:4096` |
| `fetch` | `function` | Custom fetch implementation | `globalThis.fetch` |
| `parseAs` | `string` | Response parsing method | `auto` |
| `responseStyle` | `string` | Return style: `data` or `fields` | `fields` |
| `throwOnError` | `boolean` | Throw errors instead of return | `false` |
---

View file

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