From 48b2bde6e53612c6e1458cca168f4b56c5f3b784 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 08:39:42 +1000 Subject: [PATCH 001/463] fix(win32): use path.delimiter for PATH separator in LSP server lookups (#5589) --- packages/opencode/src/lsp/server.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index bd959184b..5d7c19915 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -281,7 +281,7 @@ export namespace LSPServer { extensions: [".go"], async spawn(root) { let bin = Bun.which("gopls", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { if (!Bun.which("go")) return @@ -319,7 +319,7 @@ export namespace LSPServer { extensions: [".rb", ".rake", ".gemspec", ".ru"], async spawn(root) { let bin = Bun.which("rubocop", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { const ruby = Bun.which("ruby") @@ -470,7 +470,7 @@ export namespace LSPServer { root: NearestRoot(["build.zig"]), async spawn(root) { let bin = Bun.which("zls", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { @@ -576,7 +576,7 @@ export namespace LSPServer { extensions: [".cs"], async spawn(root) { let bin = Bun.which("csharp-ls", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { if (!Bun.which("dotnet")) { @@ -616,7 +616,7 @@ export namespace LSPServer { extensions: [".fs", ".fsi", ".fsx", ".fsscript"], async spawn(root) { let bin = Bun.which("fsautocomplete", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { if (!Bun.which("dotnet")) { @@ -1110,7 +1110,7 @@ export namespace LSPServer { extensions: [".lua"], async spawn(root) { let bin = Bun.which("lua-language-server", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { @@ -1349,7 +1349,7 @@ export namespace LSPServer { root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]), async spawn(root) { let bin = Bun.which("terraform-ls", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { @@ -1433,7 +1433,7 @@ export namespace LSPServer { root: NearestRoot([".latexmkrc", "latexmkrc", ".texlabroot", "texlabroot"]), async spawn(root) { let bin = Bun.which("texlab", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, + PATH: process.env["PATH"] + path.delimiter + Global.Path.bin, }) if (!bin) { From 4f2baf1a72ed5c17963b34fe2a63229379be59e1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 15 Dec 2025 22:40:18 +0000 Subject: [PATCH 002/463] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index de0b35048..e6aa7e5b1 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index e07226df7..9907bbf93 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From efac8cebb3e3b5abb9672d7973aa508e9d9ef0d4 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 08:47:27 +1000 Subject: [PATCH 003/463] fix(win32): correct ElixirLS extension typo (#5590) --- packages/opencode/src/lsp/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 5d7c19915..adfd94956 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -420,7 +420,7 @@ export namespace LSPServer { Global.Path.bin, "elixir-ls-master", "release", - process.platform === "win32" ? "language_server.bar" : "language_server.sh", + process.platform === "win32" ? "language_server.bat" : "language_server.sh", ) if (!(await Bun.file(binary).exists())) { From dbbcf0b8d041245a8b8feeff159d0bb9801b9924 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 15 Dec 2025 18:14:30 -0500 Subject: [PATCH 004/463] tui: fix model selection dialog to properly replace current dialog instead of creating nested dialogs --- .../desktop/src/components/prompt-input.tsx | 4 +- packages/desktop/src/context/notification.tsx | 1 + packages/ui/src/context/dialog.tsx | 70 ++++++++++--------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 840710152..f2821c3c7 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -864,7 +864,9 @@ export const PromptInput: Component = (props) => { as="div" variant="ghost" onClick={() => - dialog.push(() => (providers.paid().length > 0 ? : )) + dialog.replace(() => + providers.paid().length > 0 ? : , + ) } > {local.model.current()?.name ?? "Select model"} diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index 9843066ea..839ebfad7 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -58,6 +58,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi time: Date.now(), viewed: false, } + console.log(event) switch (event.type) { case "session.idle": { const sessionID = event.properties.sessionID diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx index fae0c57b4..50e41c596 100644 --- a/packages/ui/src/context/dialog.tsx +++ b/packages/ui/src/context/dialog.tsx @@ -1,7 +1,9 @@ import { createContext, + createEffect, createMemo, createSignal, + For, getOwner, Owner, ParentProps, @@ -11,6 +13,7 @@ import { type JSX, } from "solid-js" import { Dialog as Kobalte } from "@kobalte/core/dialog" +import { iife } from "@opencode-ai/util/iife" type DialogElement = () => JSX.Element @@ -25,23 +28,49 @@ function init() { }[] >([]) - return { + const result = { get stack() { return store() }, - push(element: DialogElement, owner: Owner, onClose?: () => void) { - setStore((s) => [...s, { element, onClose, owner }]) - }, pop() { const current = store().at(-1) + if (!current) return current?.onClose?.() - setStore((stack) => stack.slice(0, -1)) + setStore((stack) => { + stack.pop() + return [...stack] + }) }, replace(element: DialogElement, owner: Owner, onClose?: () => void) { for (const item of store()) { item.onClose?.() } - setStore([{ element, onClose, owner }]) + setStore([ + { + element: () => + runWithOwner(owner, () => ( + + { + if (!open) { + onClose?.() + result.pop() + } + }} + > + + + {element()} + + + + )), + onClose, + owner, + }, + ]) }, clear() { for (const item of store()) { @@ -50,38 +79,16 @@ function init() { setStore([]) }, } + return result } export function DialogProvider(props: ParentProps) { const ctx = init() - const last = createMemo(() => ctx.stack.at(-1)) return ( {props.children}
- - {(item) => - runWithOwner(item().owner, () => { - return ( - { - if (!open) { - item().onClose?.() - ctx.pop() - } - }} - > - - - {item().element()} - - - ) - }) - } - + {(item) => <>{item.element()}}
) @@ -103,9 +110,6 @@ export function useDialog() { replace(element: DialogElement, onClose?: () => void) { ctx.replace(element, owner, onClose) }, - push(element: DialogElement, onClose?: () => void) { - ctx.push(element, owner, onClose) - }, pop() { ctx.pop() }, From 416a919c6dd4d5d0727850c983fed7cd3273dcf5 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 15 Dec 2025 18:21:54 -0500 Subject: [PATCH 005/463] tui: fix dialog replacement to prevent nested dialogs from showing simultaneously --- packages/ui/src/context/dialog.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx index 50e41c596..b15d96991 100644 --- a/packages/ui/src/context/dialog.tsx +++ b/packages/ui/src/context/dialog.tsx @@ -22,6 +22,7 @@ const Context = createContext>() function init() { const [store, setStore] = createSignal< { + id: string element: DialogElement onClose?: () => void owner: Owner @@ -45,11 +46,13 @@ function init() { for (const item of store()) { item.onClose?.() } + const id = Math.random().toString(36) setStore([ { + id, element: () => runWithOwner(owner, () => ( - + { + console.log("store", ctx.stack.length) + }) return ( {props.children} From 002db3abf4253a7639e745a55b8b739aca5bd534 Mon Sep 17 00:00:00 2001 From: opencode Date: Mon, 15 Dec 2025 23:26:00 +0000 Subject: [PATCH 006/463] release: v1.0.160 --- bun.lock | 30 +++++++++++++------------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/tauri/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index 48c2a2129..c1f3e126f 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.0.159", + "version": "1.0.160", "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.159", + "version": "1.0.160", "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.159", + "version": "1.0.160", "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.159", + "version": "1.0.160", "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.159", + "version": "1.0.160", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -170,7 +170,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -199,7 +199,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -215,7 +215,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.159", + "version": "1.0.160", "bin": { "opencode": "./bin/opencode", }, @@ -307,7 +307,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -327,7 +327,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.159", + "version": "1.0.160", "devDependencies": { "@hey-api/openapi-ts": "0.88.1", "@tsconfig/node22": "catalog:", @@ -338,7 +338,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -351,7 +351,7 @@ }, "packages/tauri": { "name": "@opencode-ai/tauri", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@opencode-ai/desktop": "workspace:*", "@tauri-apps/api": "^2", @@ -376,7 +376,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -411,7 +411,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "zod": "catalog:", }, @@ -422,7 +422,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 67d5c33fd..5d115ef62 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.0.159", + "version": "1.0.160", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 9df796bed..087941c75 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.159", + "version": "1.0.160", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 6f4b59cdb..4c9601a76 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.159", + "version": "1.0.160", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index c12b280d6..e43ff70ba 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.159", + "version": "1.0.160", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 0b0df0076..e5083eb77 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.159", + "version": "1.0.160", "description": "", "type": "module", "exports": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 4a3308e0e..2ddc6fe59 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.0.159", + "version": "1.0.160", "private": true, "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index a2e55900b..8e69aafd8 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.0.159" +version = "1.0.160" 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.159/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.160/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.159/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.160/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.159/opencode-linux-arm64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.160/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.159/opencode-linux-x64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.160/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.159/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.160/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index edc373a96..e81aa1594 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.159", + "version": "1.0.160", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ace101a67..eb5f0acda 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.159", + "version": "1.0.160", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index e6aa7e5b1..fe0564e5b 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.159", + "version": "1.0.160", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 9907bbf93..29ddf877b 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.159", + "version": "1.0.160", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 42a38c4db..acd2592e4 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.159", + "version": "1.0.160", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index 311dc7335..f6f43ce38 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/tauri", "private": true, - "version": "1.0.159", + "version": "1.0.160", "type": "module", "scripts": { "typecheck": "tsgo -b", diff --git a/packages/ui/package.json b/packages/ui/package.json index d98000b9f..afe91de82 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.159", + "version": "1.0.160", "type": "module", "exports": { "./*": "./src/components/*.tsx", diff --git a/packages/util/package.json b/packages/util/package.json index 1e30f9411..e4392d81c 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.0.159", + "version": "1.0.160", "private": true, "type": "module", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index 4fcfb8236..cfbc8483d 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.159", + "version": "1.0.160", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 05b9d1695..9846f6307 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.159", + "version": "1.0.160", "publisher": "sst-dev", "repository": { "type": "git", From 0d1c6e0ca91af20291b39a15ed59c837b556e386 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 09:29:30 +1000 Subject: [PATCH 007/463] fix(win32): Missing LSP can now unzip on windows (#5594) --- packages/opencode/src/lsp/server.ts | 32 +++++++++++++++++---------- packages/opencode/src/util/archive.ts | 16 ++++++++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 packages/opencode/src/util/archive.ts diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index adfd94956..9ccdb6a6d 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -9,6 +9,7 @@ import fs from "fs/promises" import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" import { Flag } from "../flag/flag" +import { Archive } from "../util/archive" export namespace LSPServer { const log = Log.create({ service: "lsp.server" }) @@ -176,7 +177,7 @@ export namespace LSPServer { const zipPath = path.join(Global.Path.bin, "vscode-eslint.zip") await Bun.file(zipPath).write(response) - await $`unzip -o -q ${zipPath}`.quiet().cwd(Global.Path.bin).nothrow() + await Archive.extractZip(zipPath, Global.Path.bin) await fs.rm(zipPath, { force: true }) const extractedPath = path.join(Global.Path.bin, "vscode-eslint-main") @@ -438,7 +439,7 @@ export namespace LSPServer { const zipPath = path.join(Global.Path.bin, "elixir-ls.zip") await Bun.file(zipPath).write(response) - await $`unzip -o -q ${zipPath}`.quiet().cwd(Global.Path.bin).nothrow() + await Archive.extractZip(zipPath, Global.Path.bin) await fs.rm(zipPath, { force: true, @@ -541,7 +542,7 @@ export namespace LSPServer { await Bun.file(tempPath).write(downloadResponse) if (ext === "zip") { - await $`unzip -o -q ${tempPath}`.quiet().cwd(Global.Path.bin).nothrow() + await Archive.extractZip(tempPath, Global.Path.bin) } else { await $`tar -xf ${tempPath}`.cwd(Global.Path.bin).nothrow() } @@ -840,7 +841,7 @@ export namespace LSPServer { } if (zip) { - await $`unzip -o -q ${archive}`.quiet().cwd(Global.Path.bin).nothrow() + await Archive.extractZip(archive, Global.Path.bin) } if (tar) { await $`tar -xf ${archive}`.cwd(Global.Path.bin).nothrow() @@ -1188,14 +1189,21 @@ export namespace LSPServer { await fs.mkdir(installDir, { recursive: true }) if (ext === "zip") { - const ok = await $`unzip -o -q ${tempPath} -d ${installDir}`.quiet().catch((error) => { - log.error("Failed to extract lua-language-server archive", { error }) - }) + const ok = await Archive.extractZip(tempPath, installDir) + .then(() => true) + .catch((error) => { + log.error("Failed to extract lua-language-server archive", { error }) + return false + }) if (!ok) return } else { - const ok = await $`tar -xzf ${tempPath} -C ${installDir}`.quiet().catch((error) => { - log.error("Failed to extract lua-language-server archive", { error }) - }) + const ok = await $`tar -xzf ${tempPath} -C ${installDir}` + .quiet() + .then(() => true) + .catch((error) => { + log.error("Failed to extract lua-language-server archive", { error }) + return false + }) if (!ok) return } @@ -1396,7 +1404,7 @@ export namespace LSPServer { const tempPath = path.join(Global.Path.bin, assetName) await Bun.file(tempPath).write(downloadResponse) - await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow() + await Archive.extractZip(tempPath, Global.Path.bin) await fs.rm(tempPath, { force: true }) bin = path.join(Global.Path.bin, "terraform-ls" + (platform === "win32" ? ".exe" : "")) @@ -1481,7 +1489,7 @@ export namespace LSPServer { await Bun.file(tempPath).write(downloadResponse) if (ext === "zip") { - await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow() + await Archive.extractZip(tempPath, Global.Path.bin) } if (ext === "tar.gz") { await $`tar -xzf ${tempPath}`.cwd(Global.Path.bin).nothrow() diff --git a/packages/opencode/src/util/archive.ts b/packages/opencode/src/util/archive.ts new file mode 100644 index 000000000..34a1738a8 --- /dev/null +++ b/packages/opencode/src/util/archive.ts @@ -0,0 +1,16 @@ +import { $ } from "bun" +import path from "path" + +export namespace Archive { + export async function extractZip(zipPath: string, destDir: string) { + if (process.platform === "win32") { + const winZipPath = path.resolve(zipPath) + const winDestDir = path.resolve(destDir) + // $global:ProgressPreference suppresses PowerShell's blue progress bar popup + const cmd = `$global:ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path '${winZipPath}' -DestinationPath '${winDestDir}' -Force` + await $`powershell -NoProfile -NonInteractive -Command ${cmd}`.quiet() + } else { + await $`unzip -o -q ${zipPath} -d ${destDir}`.quiet() + } + } +} From c0c61b25ff9d9bb7551d193b59c5176fe97a67ca Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 15 Dec 2025 23:30:06 +0000 Subject: [PATCH 008/463] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index fe0564e5b..04862e081 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 29ddf877b..37e5ef906 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 89a4f1c1ae38c8fa8999fe082641e504b179684a Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 15 Dec 2025 17:41:28 -0600 Subject: [PATCH 009/463] tweak: add .catch for extractZip calls --- packages/opencode/src/lsp/server.ts | 48 +++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 9ccdb6a6d..939a31a2d 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -177,7 +177,13 @@ export namespace LSPServer { const zipPath = path.join(Global.Path.bin, "vscode-eslint.zip") await Bun.file(zipPath).write(response) - await Archive.extractZip(zipPath, Global.Path.bin) + const ok = await Archive.extractZip(zipPath, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract vscode-eslint archive", { error }) + return false + }) + if (!ok) return await fs.rm(zipPath, { force: true }) const extractedPath = path.join(Global.Path.bin, "vscode-eslint-main") @@ -439,7 +445,13 @@ export namespace LSPServer { const zipPath = path.join(Global.Path.bin, "elixir-ls.zip") await Bun.file(zipPath).write(response) - await Archive.extractZip(zipPath, Global.Path.bin) + const ok = await Archive.extractZip(zipPath, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract elixir-ls archive", { error }) + return false + }) + if (!ok) return await fs.rm(zipPath, { force: true, @@ -542,7 +554,13 @@ export namespace LSPServer { await Bun.file(tempPath).write(downloadResponse) if (ext === "zip") { - await Archive.extractZip(tempPath, Global.Path.bin) + const ok = await Archive.extractZip(tempPath, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract zls archive", { error }) + return false + }) + if (!ok) return } else { await $`tar -xf ${tempPath}`.cwd(Global.Path.bin).nothrow() } @@ -841,7 +859,13 @@ export namespace LSPServer { } if (zip) { - await Archive.extractZip(archive, Global.Path.bin) + const ok = await Archive.extractZip(archive, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract clangd archive", { error }) + return false + }) + if (!ok) return } if (tar) { await $`tar -xf ${archive}`.cwd(Global.Path.bin).nothrow() @@ -1404,7 +1428,13 @@ export namespace LSPServer { const tempPath = path.join(Global.Path.bin, assetName) await Bun.file(tempPath).write(downloadResponse) - await Archive.extractZip(tempPath, Global.Path.bin) + const ok = await Archive.extractZip(tempPath, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract terraform-ls archive", { error }) + return false + }) + if (!ok) return await fs.rm(tempPath, { force: true }) bin = path.join(Global.Path.bin, "terraform-ls" + (platform === "win32" ? ".exe" : "")) @@ -1489,7 +1519,13 @@ export namespace LSPServer { await Bun.file(tempPath).write(downloadResponse) if (ext === "zip") { - await Archive.extractZip(tempPath, Global.Path.bin) + const ok = await Archive.extractZip(tempPath, Global.Path.bin) + .then(() => true) + .catch((error) => { + log.error("Failed to extract texlab archive", { error }) + return false + }) + if (!ok) return } if (ext === "tar.gz") { await $`tar -xzf ${tempPath}`.cwd(Global.Path.bin).nothrow() From 27e826eba63a3d8d1111f13dc4934d3f54d90cf8 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:01:03 +1000 Subject: [PATCH 010/463] fix(win32): Normalise LSP paths on windows (fixes lua) (#5597) --- .../src/cli/cmd/tui/routes/session/index.tsx | 9 ++++++-- packages/opencode/src/lsp/client.ts | 22 +++++++++++-------- packages/opencode/src/tool/edit.ts | 18 +++++++-------- packages/opencode/src/tool/write.ts | 3 ++- packages/opencode/src/util/filesystem.ts | 14 ++++++++++++ 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 48f7db054..b9ef2580b 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -64,6 +64,7 @@ import { Editor } from "../../util/editor" import stripAnsi from "strip-ansi" import { Footer } from "./footer.tsx" import { usePromptRef } from "../../context/prompt" +import { Filesystem } from "@/util/filesystem" addDefaultParsers(parsers.parsers) @@ -1414,7 +1415,10 @@ ToolRegistry.register({ return props.input.content }) - const diagnostics = createMemo(() => props.metadata.diagnostics?.[props.input.filePath ?? ""] ?? []) + const diagnostics = createMemo(() => { + const filePath = Filesystem.normalizePath(props.input.filePath ?? "") + return props.metadata.diagnostics?.[filePath] ?? [] + }) return ( <> @@ -1587,7 +1591,8 @@ ToolRegistry.register({ const diffContent = createMemo(() => props.metadata.diff ?? props.permission["diff"]) const diagnostics = createMemo(() => { - const arr = props.metadata.diagnostics?.[props.input.filePath ?? ""] ?? [] + const filePath = Filesystem.normalizePath(props.input.filePath ?? "") + const arr = props.metadata.diagnostics?.[filePath] ?? [] return arr.filter((x) => x.severity === 1).slice(0, 3) }) diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index ce426cf62..f06c2c938 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -11,6 +11,7 @@ import type { LSPServer } from "./server" import { NamedError } from "@opencode-ai/util/error" import { withTimeout } from "../util/timeout" import { Instance } from "../project/instance" +import { Filesystem } from "../util/filesystem" export namespace LSPClient { const log = Log.create({ service: "lsp.client" }) @@ -47,14 +48,15 @@ export namespace LSPClient { const diagnostics = new Map() connection.onNotification("textDocument/publishDiagnostics", (params) => { - const path = fileURLToPath(params.uri) + const filePath = Filesystem.normalizePath(fileURLToPath(params.uri)) l.info("textDocument/publishDiagnostics", { - path, + path: filePath, + count: params.diagnostics.length, }) - const exists = diagnostics.has(path) - diagnostics.set(path, params.diagnostics) + const exists = diagnostics.has(filePath) + diagnostics.set(filePath, params.diagnostics) if (!exists && input.serverID === "typescript") return - Bus.publish(Event.Diagnostics, { path, serverID: input.serverID }) + Bus.publish(Event.Diagnostics, { path: filePath, serverID: input.serverID }) }) connection.onRequest("window/workDoneProgress/create", (params) => { l.info("window/workDoneProgress/create", params) @@ -181,14 +183,16 @@ export namespace LSPClient { return diagnostics }, async waitForDiagnostics(input: { path: string }) { - input.path = path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path) - log.info("waiting for diagnostics", input) + const normalizedPath = Filesystem.normalizePath( + path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path), + ) + log.info("waiting for diagnostics", { path: normalizedPath }) let unsub: () => void return await withTimeout( new Promise((resolve) => { unsub = Bus.subscribe(Event.Diagnostics, (event) => { - if (event.properties.path === input.path && event.properties.serverID === result.serverID) { - log.info("got diagnostics", input) + if (event.properties.path === normalizedPath && event.properties.serverID === result.serverID) { + log.info("got diagnostics", { path: normalizedPath }) unsub?.() resolve() } diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index fdf115ac4..b49bd7abe 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -140,16 +140,14 @@ export const EditTool = Tool.define("edit", { let output = "" await LSP.touchFile(filePath, true) const diagnostics = await LSP.diagnostics() - for (const [file, issues] of Object.entries(diagnostics)) { - if (issues.length === 0) continue - if (file === filePath) { - const errors = issues.filter((item) => item.severity === 1) - const limited = errors.slice(0, MAX_DIAGNOSTICS_PER_FILE) - const suffix = - errors.length > MAX_DIAGNOSTICS_PER_FILE ? `\n... and ${errors.length - MAX_DIAGNOSTICS_PER_FILE} more` : "" - output += `\nThis file has errors, please fix\n\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n\n` - continue - } + const normalizedFilePath = Filesystem.normalizePath(filePath) + const issues = diagnostics[normalizedFilePath] ?? [] + if (issues.length > 0) { + const errors = issues.filter((item) => item.severity === 1) + const limited = errors.slice(0, MAX_DIAGNOSTICS_PER_FILE) + const suffix = + errors.length > MAX_DIAGNOSTICS_PER_FILE ? `\n... and ${errors.length - MAX_DIAGNOSTICS_PER_FILE} more` : "" + output += `\nThis file has errors, please fix\n\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n\n` } const filediff: Snapshot.FileDiff = { diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index 03f2ba891..6b8fd3dd1 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -80,6 +80,7 @@ export const WriteTool = Tool.define("write", { let output = "" await LSP.touchFile(filepath, true) const diagnostics = await LSP.diagnostics() + const normalizedFilepath = Filesystem.normalizePath(filepath) let projectDiagnosticsCount = 0 for (const [file, issues] of Object.entries(diagnostics)) { if (issues.length === 0) continue @@ -87,7 +88,7 @@ export const WriteTool = Tool.define("write", { const limited = sorted.slice(0, MAX_DIAGNOSTICS_PER_FILE) const suffix = issues.length > MAX_DIAGNOSTICS_PER_FILE ? `\n... and ${issues.length - MAX_DIAGNOSTICS_PER_FILE} more` : "" - if (file === filepath) { + if (file === normalizedFilepath) { output += `\nThis file has errors, please fix\n\n${limited.map(LSP.Diagnostic.pretty).join("\n")}${suffix}\n\n` continue } diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index a3dcfc703..98fbe533d 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -1,7 +1,21 @@ +import { realpathSync } from "fs" import { exists } from "fs/promises" import { dirname, join, relative } from "path" export namespace Filesystem { + /** + * On Windows, normalize a path to its canonical casing using the filesystem. + * This is needed because Windows paths are case-insensitive but LSP servers + * may return paths with different casing than what we send them. + */ + export function normalizePath(p: string): string { + if (process.platform !== "win32") return p + try { + return realpathSync.native(p) + } catch { + return p + } + } export function overlaps(a: string, b: string) { const relA = relative(a, b) const relB = relative(b, a) From 34024c2504d1bdb105e217f5351fd1cb5d7b50a9 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:04:47 -0600 Subject: [PATCH 011/463] docs: models --refresh flag in cli.mdx (#5596) Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node --- packages/web/src/content/docs/cli.mdx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 64e11ff56..777d377a7 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -161,13 +161,32 @@ opencode github run List all available models from configured providers. ```bash -opencode models +opencode models [provider] ``` This command displays all models available across your configured providers in the format `provider/model`. This is useful for figuring out the exact model name to use in [your config](/docs/config/). +You can optionally pass a provider ID to filter models by that provider. + +```bash +opencode models anthropic +``` + +#### Flags + +| Flag | Description | +| ----------- | ------------------------------------------------------------ | +| `--refresh` | Refresh the models cache from models.dev | +| `--verbose` | Use more verbose model output (includes metadata like costs) | + +Use the `--refresh` flag to update the cached model list. This is useful when new models have been added to a provider and you want to see them in OpenCode. + +```bash +opencode models --refresh +``` + --- ### run From 2c70c0b00fdf7561d1a936043223da8518acde08 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:13:11 -0600 Subject: [PATCH 012/463] fix: undefined events --- packages/desktop/src/context/global-sync.tsx | 1 + packages/desktop/src/context/notification.tsx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/desktop/src/context/global-sync.tsx index 7d8186a68..ad3a3bf18 100644 --- a/packages/desktop/src/context/global-sync.tsx +++ b/packages/desktop/src/context/global-sync.tsx @@ -138,6 +138,7 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple } globalSDK.event.listen((e) => { + console.log(e) const directory = e.name const event = e.details diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index 839ebfad7..045361630 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -51,6 +51,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi // }) globalSDK.event.listen((e) => { + console.log(e) const directory = e.name const event = e.details const base = { @@ -58,8 +59,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi time: Date.now(), viewed: false, } - console.log(event) - switch (event.type) { + switch (event?.type) { case "session.idle": { const sessionID = event.properties.sessionID const [syncStore] = globalSync.child(directory) From 0dce5173ccca05aa7bd9eaabab78fe1f5f4d4360 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 16 Dec 2025 00:17:15 +0000 Subject: [PATCH 013/463] release: v1.0.161 --- bun.lock | 30 +++++++++++++------------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/tauri/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index c1f3e126f..2e725f84d 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.0.160", + "version": "1.0.161", "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.160", + "version": "1.0.161", "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.160", + "version": "1.0.161", "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.160", + "version": "1.0.161", "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.160", + "version": "1.0.161", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -170,7 +170,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -199,7 +199,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -215,7 +215,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.160", + "version": "1.0.161", "bin": { "opencode": "./bin/opencode", }, @@ -307,7 +307,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -327,7 +327,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.160", + "version": "1.0.161", "devDependencies": { "@hey-api/openapi-ts": "0.88.1", "@tsconfig/node22": "catalog:", @@ -338,7 +338,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -351,7 +351,7 @@ }, "packages/tauri": { "name": "@opencode-ai/tauri", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@opencode-ai/desktop": "workspace:*", "@tauri-apps/api": "^2", @@ -376,7 +376,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -411,7 +411,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "zod": "catalog:", }, @@ -422,7 +422,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 5d115ef62..2e798e7e3 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.0.160", + "version": "1.0.161", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 087941c75..216940aa1 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.160", + "version": "1.0.161", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 4c9601a76..54e422ed6 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.160", + "version": "1.0.161", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index e43ff70ba..729232654 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.160", + "version": "1.0.161", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index e5083eb77..fb476def8 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.160", + "version": "1.0.161", "description": "", "type": "module", "exports": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 2ddc6fe59..951ea4249 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.0.160", + "version": "1.0.161", "private": true, "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 8e69aafd8..6eb29831f 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.0.160" +version = "1.0.161" 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.160/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.161/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.160/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.161/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.160/opencode-linux-arm64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.161/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.160/opencode-linux-x64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.161/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.160/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.161/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index e81aa1594..90d6d0e5e 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.160", + "version": "1.0.161", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index eb5f0acda..786728cdd 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.160", + "version": "1.0.161", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 04862e081..39408bf28 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.160", + "version": "1.0.161", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 37e5ef906..a57526874 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.160", + "version": "1.0.161", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index acd2592e4..57bd7b403 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.160", + "version": "1.0.161", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index f6f43ce38..2729d987f 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/tauri", "private": true, - "version": "1.0.160", + "version": "1.0.161", "type": "module", "scripts": { "typecheck": "tsgo -b", diff --git a/packages/ui/package.json b/packages/ui/package.json index afe91de82..3ea3cdee5 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.160", + "version": "1.0.161", "type": "module", "exports": { "./*": "./src/components/*.tsx", diff --git a/packages/util/package.json b/packages/util/package.json index e4392d81c..4d4a76b32 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.0.160", + "version": "1.0.161", "private": true, "type": "module", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index cfbc8483d..f1e781f43 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.160", + "version": "1.0.161", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 9846f6307..8c1c0f323 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.160", + "version": "1.0.161", "publisher": "sst-dev", "repository": { "type": "git", From 112c58abf516e4523fb698b868a710c40b271559 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 15 Dec 2025 19:33:17 -0500 Subject: [PATCH 014/463] tui: refactor dialog system to use single active dialog instead of stack --- .../components/dialog-connect-provider.tsx | 22 ++-- .../src/components/dialog-select-file.tsx | 2 +- .../components/dialog-select-model-unpaid.tsx | 6 +- .../src/components/dialog-select-model.tsx | 6 +- .../src/components/dialog-select-provider.tsx | 2 +- .../desktop/src/components/prompt-input.tsx | 4 +- packages/desktop/src/context/command.tsx | 6 +- packages/desktop/src/context/notification.tsx | 2 +- packages/desktop/src/pages/layout.tsx | 2 +- packages/desktop/src/pages/session.tsx | 8 +- packages/ui/src/context/dialog.tsx | 122 +++++++----------- 11 files changed, 78 insertions(+), 104 deletions(-) diff --git a/packages/desktop/src/components/dialog-connect-provider.tsx b/packages/desktop/src/components/dialog-connect-provider.tsx index 4660e1398..0d6737815 100644 --- a/packages/desktop/src/components/dialog-connect-provider.tsx +++ b/packages/desktop/src/components/dialog-connect-provider.tsx @@ -108,20 +108,18 @@ export function DialogConnectProvider(props: { provider: string }) { async function complete() { await globalSDK.client.global.dispose() - setTimeout(() => { - showToast({ - variant: "success", - icon: "circle-check", - title: `${provider().name} connected`, - description: `${provider().name} models are now available to use.`, - }) - dialog.replace(() => ) - }, 1000) + dialog.close() + showToast({ + variant: "success", + icon: "circle-check", + title: `${provider().name} connected`, + description: `${provider().name} models are now available to use.`, + }) } function goBack() { if (methods().length === 1) { - dialog.replace(() => ) + dialog.show(() => ) return } if (store.authorization) { @@ -133,7 +131,7 @@ export function DialogConnectProvider(props: { provider: string }) { setStore("methodIndex", undefined) return } - dialog.replace(() => ) + dialog.show(() => ) } return ( @@ -352,7 +350,7 @@ export function DialogConnectProvider(props: { provider: string }) { }) if (result.error) { // TODO: show error - dialog.clear() + dialog.close() return } await complete() diff --git a/packages/desktop/src/components/dialog-select-file.tsx b/packages/desktop/src/components/dialog-select-file.tsx index b719e15d2..61c518719 100644 --- a/packages/desktop/src/components/dialog-select-file.tsx +++ b/packages/desktop/src/components/dialog-select-file.tsx @@ -27,7 +27,7 @@ export function DialogSelectFile() { if (path) { tabs().open("file://" + path) } - dialog.clear() + dialog.close() }} > {(i) => ( diff --git a/packages/desktop/src/components/dialog-select-model-unpaid.tsx b/packages/desktop/src/components/dialog-select-model-unpaid.tsx index 7cdb24915..77e493d3c 100644 --- a/packages/desktop/src/components/dialog-select-model-unpaid.tsx +++ b/packages/desktop/src/components/dialog-select-model-unpaid.tsx @@ -42,7 +42,7 @@ export const DialogSelectModelUnpaid: Component = () => { local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true, }) - dialog.clear() + dialog.close() }} > {(i) => ( @@ -75,7 +75,7 @@ export const DialogSelectModelUnpaid: Component = () => { }} onSelect={(x) => { if (!x) return - dialog.replace(() => ) + dialog.show(() => ) }} > {(i) => ( @@ -105,7 +105,7 @@ export const DialogSelectModelUnpaid: Component = () => { class="w-full justify-start px-[11px] py-3.5 gap-4.5 text-14-medium" icon="dot-grid" onClick={() => { - dialog.replace(() => ) + dialog.show(() => ) }} > View all providers diff --git a/packages/desktop/src/components/dialog-select-model.tsx b/packages/desktop/src/components/dialog-select-model.tsx index f0b2e6db9..622ab15fb 100644 --- a/packages/desktop/src/components/dialog-select-model.tsx +++ b/packages/desktop/src/components/dialog-select-model.tsx @@ -28,7 +28,7 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => { class="h-7 -my-1 text-14-medium" icon="plus-small" tabIndex={-1} - onClick={() => dialog.replace(() => )} + onClick={() => dialog.show(() => )} > Connect provider @@ -57,7 +57,7 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => { local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true, }) - dialog.clear() + dialog.close() }} > {(i) => ( @@ -75,7 +75,7 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => { diff --git a/packages/desktop/src/components/dialog-select-provider.tsx b/packages/desktop/src/components/dialog-select-provider.tsx index 8da10b1d5..52fac7073 100644 --- a/packages/desktop/src/components/dialog-select-provider.tsx +++ b/packages/desktop/src/components/dialog-select-provider.tsx @@ -34,7 +34,7 @@ export const DialogSelectProvider: Component = () => { }} onSelect={(x) => { if (!x) return - dialog.replace(() => ) + dialog.show(() => ) }} > {(i) => ( diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index f2821c3c7..6e147242d 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -864,9 +864,7 @@ export const PromptInput: Component = (props) => { as="div" variant="ghost" onClick={() => - dialog.replace(() => - providers.paid().length > 0 ? : , - ) + dialog.show(() => (providers.paid().length > 0 ? : )) } > {local.model.current()?.name ?? "Select model"} diff --git a/packages/desktop/src/context/command.tsx b/packages/desktop/src/context/command.tsx index d4ef8e166..8fd76ee21 100644 --- a/packages/desktop/src/context/command.tsx +++ b/packages/desktop/src/context/command.tsx @@ -128,7 +128,7 @@ function DialogCommand(props: { options: CommandOption[] }) { groupBy={(x) => x.category ?? ""} onSelect={(option) => { if (option) { - dialog.clear() + dialog.close() option.onSelect?.("palette") } }} @@ -174,8 +174,8 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex const suspended = () => suspendCount() > 0 const showPalette = () => { - if (dialog.stack.length === 0) { - dialog.replace(() => !x.disabled)} />) + if (!dialog.active) { + dialog.show(() => !x.disabled)} />) } } diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index 045361630..ee15bc34a 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -59,7 +59,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi time: Date.now(), viewed: false, } - switch (event?.type) { + switch (event.type) { case "session.idle": { const sessionID = event.properties.sessionID const [syncStore] = globalSync.child(directory) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 2f0c6e050..27852967a 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -217,7 +217,7 @@ export default function Layout(props: ParentProps) { ]) function connectProvider() { - dialog.replace(() => ) + dialog.show(() => ) } function navigateToProject(directory: string | undefined) { diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 9167ef7b7..390872d36 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -176,7 +176,7 @@ export default function Page() { category: "File", keybind: "mod+p", slash: "open", - onSelect: () => dialog.replace(() => ), + onSelect: () => dialog.show(() => ), }, // { // id: "theme.toggle", @@ -245,7 +245,7 @@ export default function Page() { category: "Model", keybind: "mod+'", slash: "model", - onSelect: () => dialog.replace(() => ), + onSelect: () => dialog.show(() => ), }, { id: "agent.cycle", @@ -320,7 +320,7 @@ export default function Page() { const handleKeyDown = (event: KeyboardEvent) => { if ((document.activeElement as HTMLElement)?.dataset?.component === "terminal") return - if (dialog.stack.length > 0) return + if (dialog.active) return if (event.key === "PageUp" || event.key === "PageDown") { const scrollContainer = document.querySelector('[data-slot="session-turn-content"]') as HTMLElement @@ -613,7 +613,7 @@ export default function Page() { icon="plus-small" variant="ghost" iconSize="large" - onClick={() => dialog.replace(() => )} + onClick={() => dialog.show(() => )} /> diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx index b15d96991..71fc63806 100644 --- a/packages/ui/src/context/dialog.tsx +++ b/packages/ui/src/context/dialog.tsx @@ -1,9 +1,7 @@ import { createContext, createEffect, - createMemo, createSignal, - For, getOwner, Owner, ParentProps, @@ -13,74 +11,59 @@ import { type JSX, } from "solid-js" import { Dialog as Kobalte } from "@kobalte/core/dialog" -import { iife } from "@opencode-ai/util/iife" type DialogElement = () => JSX.Element const Context = createContext>() function init() { - const [store, setStore] = createSignal< - { - id: string - element: DialogElement - onClose?: () => void - owner: Owner - }[] - >([]) + const [active, setActive] = createSignal< + | { + id: string + element: DialogElement + onClose?: () => void + owner: Owner + } + | undefined + >() const result = { - get stack() { - return store() + get active() { + return active() }, - pop() { - const current = store().at(-1) - if (!current) return - current?.onClose?.() - setStore((stack) => { - stack.pop() - return [...stack] + close() { + active()?.onClose?.() + setActive(undefined) + }, + show(element: DialogElement, owner: Owner, onClose?: () => void) { + active()?.onClose?.() + const id = Math.random().toString(36).slice(2) + setActive({ + id, + element: () => + runWithOwner(owner, () => ( + + { + if (!open) { + console.log("closing") + result.close() + } + }} + > + + + {element()} + + + + )), + onClose, + owner, }) }, - replace(element: DialogElement, owner: Owner, onClose?: () => void) { - for (const item of store()) { - item.onClose?.() - } - const id = Math.random().toString(36) - setStore([ - { - id, - element: () => - runWithOwner(owner, () => ( - - { - if (!open) { - onClose?.() - result.pop() - } - }} - > - - - {element()} - - - - )), - onClose, - owner, - }, - ]) - }, - clear() { - for (const item of store()) { - item.onClose?.() - } - setStore([]) - }, } return result @@ -89,14 +72,12 @@ function init() { export function DialogProvider(props: ParentProps) { const ctx = init() createEffect(() => { - console.log("store", ctx.stack.length) + console.log("active", ctx.active) }) return ( {props.children} -
- {(item) => <>{item.element()}} -
+
{ctx.active?.element?.()}
) } @@ -111,17 +92,14 @@ export function useDialog() { throw new Error("useDialog must be used within a DialogProvider") } return { - get stack() { - return ctx.stack + get active() { + return ctx.active }, - replace(element: DialogElement, onClose?: () => void) { - ctx.replace(element, owner, onClose) + show(element: DialogElement, onClose?: () => void) { + ctx.show(element, owner, onClose) }, - pop() { - ctx.pop() - }, - clear() { - ctx.clear() + close() { + ctx.close() }, } } From 38c5f23f4a72a3e429a11da865fd0cc5df946f58 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 15 Dec 2025 19:33:19 -0500 Subject: [PATCH 015/463] tui: update dialog context and server to use new single dialog system --- packages/opencode/src/server/server.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 0cbea9658..f1d4ecd8d 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -127,8 +127,10 @@ export namespace Server { return streamSSE(c, async (stream) => { stream.writeSSE({ data: JSON.stringify({ - type: "server.connected", - properties: {}, + payload: { + type: "server.connected", + properties: {}, + }, }), }) async function handler(event: any) { From 2e25fe9d5d8df86f3b1a807ad1f7743632dac07a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 16 Dec 2025 00:36:01 +0000 Subject: [PATCH 016/463] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 39408bf28..9bed08db3 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index a57526874..3a83514c1 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 92fe9277859afa2d0bd2c47282bc4c248f017aa2 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 16 Dec 2025 00:40:27 +0000 Subject: [PATCH 017/463] release: v1.0.162 --- bun.lock | 30 +++++++++++++------------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/tauri/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index 2e725f84d..3c48017fc 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.0.161", + "version": "1.0.162", "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.161", + "version": "1.0.162", "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.161", + "version": "1.0.162", "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.161", + "version": "1.0.162", "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.161", + "version": "1.0.162", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -170,7 +170,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -199,7 +199,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -215,7 +215,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.161", + "version": "1.0.162", "bin": { "opencode": "./bin/opencode", }, @@ -307,7 +307,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -327,7 +327,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.161", + "version": "1.0.162", "devDependencies": { "@hey-api/openapi-ts": "0.88.1", "@tsconfig/node22": "catalog:", @@ -338,7 +338,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -351,7 +351,7 @@ }, "packages/tauri": { "name": "@opencode-ai/tauri", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@opencode-ai/desktop": "workspace:*", "@tauri-apps/api": "^2", @@ -376,7 +376,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -411,7 +411,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "zod": "catalog:", }, @@ -422,7 +422,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 2e798e7e3..d0f7aac82 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.0.161", + "version": "1.0.162", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 216940aa1..02e3a6de3 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.161", + "version": "1.0.162", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 54e422ed6..e80959975 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.161", + "version": "1.0.162", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 729232654..2a244c47f 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.161", + "version": "1.0.162", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index fb476def8..fce5715c7 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.161", + "version": "1.0.162", "description": "", "type": "module", "exports": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 951ea4249..89243ffeb 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.0.161", + "version": "1.0.162", "private": true, "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 6eb29831f..782f989ba 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.0.161" +version = "1.0.162" 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.161/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.162/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.161/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.162/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.161/opencode-linux-arm64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.162/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.161/opencode-linux-x64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.162/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.161/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.162/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 90d6d0e5e..6e02eb9ea 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.161", + "version": "1.0.162", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 786728cdd..cc5e45db8 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.161", + "version": "1.0.162", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 9bed08db3..6785e568f 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.161", + "version": "1.0.162", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 3a83514c1..981103b80 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.161", + "version": "1.0.162", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 57bd7b403..8a07fad12 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.161", + "version": "1.0.162", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index 2729d987f..658d173a1 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/tauri", "private": true, - "version": "1.0.161", + "version": "1.0.162", "type": "module", "scripts": { "typecheck": "tsgo -b", diff --git a/packages/ui/package.json b/packages/ui/package.json index 3ea3cdee5..8ede50bc1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.161", + "version": "1.0.162", "type": "module", "exports": { "./*": "./src/components/*.tsx", diff --git a/packages/util/package.json b/packages/util/package.json index 4d4a76b32..02c01dd24 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.0.161", + "version": "1.0.162", "private": true, "type": "module", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index f1e781f43..2ae1be84b 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.161", + "version": "1.0.162", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 8c1c0f323..2611adef0 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.161", + "version": "1.0.162", "publisher": "sst-dev", "repository": { "type": "git", From bfb254dac6f8a3ea217f5393a33d87c030b12b6d Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 15 Dec 2025 19:15:40 -0600 Subject: [PATCH 018/463] ci: auto triage issues --- .github/workflows/auto-label-tui.yml | 63 ---------------------- .github/workflows/triage.yml | 32 +++++++++++ .opencode/agent/triage.md | 12 +++++ .opencode/env.d.ts | 4 ++ .opencode/opencode.jsonc | 3 ++ .opencode/tool/github-triage.ts | 51 ++++++++++++++++++ .opencode/tool/github-triage.txt | 79 ++++++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 63 deletions(-) delete mode 100644 .github/workflows/auto-label-tui.yml create mode 100644 .github/workflows/triage.yml create mode 100644 .opencode/agent/triage.md create mode 100644 .opencode/env.d.ts create mode 100644 .opencode/tool/github-triage.ts create mode 100644 .opencode/tool/github-triage.txt diff --git a/.github/workflows/auto-label-tui.yml b/.github/workflows/auto-label-tui.yml deleted file mode 100644 index c2f81a380..000000000 --- a/.github/workflows/auto-label-tui.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Auto-label TUI Issues - -on: - issues: - types: [opened] - -jobs: - auto-label: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: write - steps: - - name: Auto-label and assign issues - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const issue = context.payload.issue; - const title = issue.title; - const description = issue.body || ''; - - // Check for "opencode web" keyword - const webPattern = /(opencode web)/i; - const isWebRelated = webPattern.test(title) || webPattern.test(description); - - // Check for version patterns like v1.0.x or 1.0.x - const versionPattern = /[v]?1\.0\./i; - const isVersionRelated = versionPattern.test(title) || versionPattern.test(description); - - // Check for "nix" keyword - const nixPattern = /\bnix\b/i; - const isNixRelated = nixPattern.test(title) || nixPattern.test(description); - - const labels = []; - - if (isWebRelated) { - labels.push('web'); - - // Assign to adamdotdevin - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - assignees: ['adamdotdevin'] - }); - } else if (isVersionRelated) { - // Only add opentui if NOT web-related - labels.push('opentui'); - } - - if (isNixRelated) { - labels.push('nix'); - } - - if (labels.length > 0) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - labels: labels - }); - } diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml new file mode 100644 index 000000000..2900137f0 --- /dev/null +++ b/.github/workflows/triage.yml @@ -0,0 +1,32 @@ +name: Issue Triage + +on: + issues: + types: [opened] + +jobs: + triage: + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + issues: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Triage issue + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + opencode run --agent triage "The following issue was just opened, triage it: + + Title: ${{ github.event.issue.title }} + + ${{ github.event.issue.body }}" diff --git a/.opencode/agent/triage.md b/.opencode/agent/triage.md new file mode 100644 index 000000000..13c73ce45 --- /dev/null +++ b/.opencode/agent/triage.md @@ -0,0 +1,12 @@ +--- +mode: primary +hidden: true +model: opencode/claude-haiku-4-5 +tools: + "*": false + "github-triage": true +--- + +You are a triage agent responsible for triaging github issues. + +Use your github-triage tool to triage issues. diff --git a/.opencode/env.d.ts b/.opencode/env.d.ts new file mode 100644 index 000000000..f2b13a934 --- /dev/null +++ b/.opencode/env.d.ts @@ -0,0 +1,4 @@ +declare module "*.txt" { + const content: string + export default content +} diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index d5d97f4c9..cbcbb0c65 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -11,4 +11,7 @@ }, }, "mcp": {}, + "tools": { + "github-triage": false, + }, } diff --git a/.opencode/tool/github-triage.ts b/.opencode/tool/github-triage.ts new file mode 100644 index 000000000..f0437e623 --- /dev/null +++ b/.opencode/tool/github-triage.ts @@ -0,0 +1,51 @@ +import { Octokit } from "@octokit/rest" +import { tool } from "@opencode-ai/plugin" +import DESCRIPTION from "./github-triage.txt" + +function getIssueNumber(): number { + const issue = parseInt(process.env.ISSUE_NUMBER ?? "", 10) + if (!issue) throw new Error("ISSUE_NUMBER env var not set") + return issue +} + +export default tool({ + description: DESCRIPTION, + args: { + assignee: tool.schema + .enum(["thdxr", "adamdotdevin", "rekram1-node", "fwang", "jayair", "kommander"]) + .describe("The username of the assignee") + .default("rekram1-node"), + labels: tool.schema + .array(tool.schema.enum(["nix", "opentui", "perf", "web", "zen", "docs"])) + .describe("The labels(s) to add to the issue") + .optional(), + }, + async execute(args) { + const issue = getIssueNumber() + const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }) + const owner = "sst" + const repo = "opencode" + + const results: string[] = [] + + await octokit.rest.issues.addAssignees({ + owner, + repo, + issue_number: issue, + assignees: [args.assignee], + }) + results.push(`Assigned @${args.assignee} to issue #${issue}`) + + if (args.labels && args.labels.length > 0) { + await octokit.rest.issues.addLabels({ + owner, + repo, + issue_number: issue, + labels: args.labels, + }) + results.push(`Added labels: ${args.labels.join(", ")}`) + } + + return results.join("\n") + }, +}) diff --git a/.opencode/tool/github-triage.txt b/.opencode/tool/github-triage.txt new file mode 100644 index 000000000..78b78a7ce --- /dev/null +++ b/.opencode/tool/github-triage.txt @@ -0,0 +1,79 @@ +Use this tool to assign and/or label a Github issue. + +You can assign the following users: +- thdxr +- adamdotdevin +- fwang +- jayair +- kommander +- rekram1-node + + +You can use the following labels: +- nix +- opentui +- perf +- web +- zen +- docs + +Always try to assign an issue, if in doubt, assign rekram1-node to it. + +## Breakdown of responsibilities: + +### thdxr + +Dax is responsible for managing core parts of the application, for large feature requests, api changes, or things that require significant changes to the codebase assign him. + +This relates to OpenCode server primarily but has overlap with just about anything + +### adamdotdevin + +Adam is responsible for managing the Desktop/Web app. If there is an issue relating to the desktop app or `opencode web` command. Assign him. + +### fwang + +Frank is responsible for managing Zen, if you see complaints about OpenCode Zen, maybe it's the dashboard, the model quality, billing issues, etc. Assign him to the issue. + +### jayair + +Jay is responsible for documentation. If there is an issue relating to documentation assign him. + +### kommander + +Sebastian is responsible for managing an OpenTUI (a library for building terminal user interfaces). OpenCode's TUI is built with OpenTUI. If there are issues abou: +- random characters on screen +- keybinds not working on different terminals +- general terminal stuff +Then assign the issue to Him. + +### rekram1-node + +Assign Aiden to an issue as a catch all, if you can't assign anyone else. Most of the time this will be bugs/polish things. +If no one else makes sense to assign, assign rekram1-node to it. + +## Breakdown of Labels: + +### nix + +Any issue that mentions nix, or nixos should have a nix label + +### opentui + +Anything relating to the TUI itself should have an opentui label + +### perf + +Anything related to slow performance, high ram, high cpu usage, or any other performance related issue should have a perf label + +### web + +Anything related to `opencode web` or the desktop app should have a web label + +### zen + +Anything related to OpenCode Zen, billing, or model quality from Zen should have a zen label + +### docs + +Anything related to the documentation should have a docs label From 0e1c711c4e5af25bf530c7c4d6e0b032d093bf66 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 16 Dec 2025 01:16:20 +0000 Subject: [PATCH 019/463] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 6785e568f..903808ae5 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 981103b80..78a81d99c 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From ff0564735062c90f9f591e067fd0e7cc470bb966 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 15 Dec 2025 19:18:28 -0600 Subject: [PATCH 020/463] ci: ignore --- .opencode/bun.lock | 49 ++++++++++++++++++++++++++++++++++++++++++ .opencode/package.json | 6 ++++++ 2 files changed, 55 insertions(+) create mode 100644 .opencode/bun.lock create mode 100644 .opencode/package.json diff --git a/.opencode/bun.lock b/.opencode/bun.lock new file mode 100644 index 000000000..cbc88dbe6 --- /dev/null +++ b/.opencode/bun.lock @@ -0,0 +1,49 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "dependencies": { + "@octokit/rest": "^22.0.1", + "@opencode-ai/plugin": "0.0.0-dev-202512160036", + }, + }, + }, + "packages": { + "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], + + "@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], + + "@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], + + "@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], + + "@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@14.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw=="], + + "@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], + + "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@17.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw=="], + + "@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], + + "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], + + "@octokit/rest": ["@octokit/rest@22.0.1", "", { "dependencies": { "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0" } }, "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw=="], + + "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], + + "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160036", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160036", "zod": "4.1.8" } }, "sha512-6FVQIsC4myRGtH5b80BG2122EDFNDh0TaLfiSl5frssEPGfR/Sny54ZUB0dy9tbqYD8sVA34z2lb34dsyyFfmg=="], + + "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160036", "", {}, "sha512-OHQjEZcBLUPIIxtb2RyTRedTw8FaiQwTRopAzOPocHLDiij9E5rco99LflYX8OuBMJQaH/1YTilVs6ZErTsuIQ=="], + + "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + + "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], + + "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], + + "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], + } +} diff --git a/.opencode/package.json b/.opencode/package.json new file mode 100644 index 000000000..d98a0245d --- /dev/null +++ b/.opencode/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@octokit/rest": "^22.0.1", + "@opencode-ai/plugin": "0.0.0-dev-202512160036" + } +} From d118782a10d389dcc67835e5af756186270be206 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 15 Dec 2025 19:24:30 -0600 Subject: [PATCH 021/463] ci: cheaper model --- .opencode/agent/triage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.opencode/agent/triage.md b/.opencode/agent/triage.md index 13c73ce45..6a020532f 100644 --- a/.opencode/agent/triage.md +++ b/.opencode/agent/triage.md @@ -1,7 +1,7 @@ --- mode: primary hidden: true -model: opencode/claude-haiku-4-5 +model: opencode/gpt-5-nano tools: "*": false "github-triage": true From 0dc62d5dadb75266d1630fc85d0e95a309097f15 Mon Sep 17 00:00:00 2001 From: Lucas Duailibe Date: Mon, 15 Dec 2025 22:58:07 -0300 Subject: [PATCH 022/463] make install script use tmp dir (#5601) --- install | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/install b/install index c6f209734..115ac169a 100755 --- a/install +++ b/install @@ -240,22 +240,23 @@ download_with_progress() { download_and_install() { print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" - mkdir -p opencodetmp && cd opencodetmp + local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" + mkdir -p "$tmp_dir" - if [[ "$os" == "windows" ]] || ! download_with_progress "$url" "$filename"; then + if [[ "$os" == "windows" ]] || ! download_with_progress "$url" "$tmp_dir/$filename"; then # Fallback to standard curl on Windows or if custom progress fails - curl -# -L -o "$filename" "$url" + curl -# -L -o "$tmp_dir/$filename" "$url" fi if [ "$os" = "linux" ]; then - tar -xzf "$filename" + tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" else - unzip -q "$filename" + unzip -q "$tmp_dir/$filename" -d "$tmp_dir" fi - mv opencode "$INSTALL_DIR" + mv "$tmp_dir/opencode" "$INSTALL_DIR" chmod 755 "${INSTALL_DIR}/opencode" - cd .. && rm -rf opencodetmp + rm -rf "$tmp_dir" } check_version From 72ebaeb8f7e5ac86b9b2d876658ff3fff4638b25 Mon Sep 17 00:00:00 2001 From: DS <78942835+Tarquinen@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:59:55 -0500 Subject: [PATCH 023/463] fix: rejoin system prompt if experimental plugin hook triggers to preserve caching (#5550) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- packages/opencode/src/session/llm.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index f95690420..ce7b60f0a 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -60,11 +60,18 @@ export namespace LLM { .join("\n"), ) + const header = system[0] const original = clone(system) await Plugin.trigger("experimental.chat.system.transform", {}, { system }) if (system.length === 0) { system.push(...original) } + // rejoin to maintain 2-part structure for caching if header unchanged + if (system.length > 2 && system[0] === header) { + const rest = system.slice(1) + system.length = 0 + system.push(header, rest.join("\n")) + } const params = await Plugin.trigger( "chat.params", From ef78fd8bae991cc7d816dba8e2f37916cc6dd441 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:26:59 +1000 Subject: [PATCH 024/463] fix: debounce LSP diagnostics to get complete results (#5600) --- packages/opencode/src/lsp/client.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index f06c2c938..b66bb9933 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -13,6 +13,8 @@ import { withTimeout } from "../util/timeout" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" +const DIAGNOSTICS_DEBOUNCE_MS = 150 + export namespace LSPClient { const log = Log.create({ service: "lsp.client" }) @@ -188,13 +190,18 @@ export namespace LSPClient { ) log.info("waiting for diagnostics", { path: normalizedPath }) let unsub: () => void + let debounceTimer: ReturnType | undefined return await withTimeout( new Promise((resolve) => { unsub = Bus.subscribe(Event.Diagnostics, (event) => { if (event.properties.path === normalizedPath && event.properties.serverID === result.serverID) { - log.info("got diagnostics", { path: normalizedPath }) - unsub?.() - resolve() + // Debounce to allow LSP to send follow-up diagnostics (e.g., semantic after syntax) + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => { + log.info("got diagnostics", { path: normalizedPath }) + unsub?.() + resolve() + }, DIAGNOSTICS_DEBOUNCE_MS) } }) }), @@ -202,6 +209,7 @@ export namespace LSPClient { ) .catch(() => {}) .finally(() => { + if (debounceTimer) clearTimeout(debounceTimer) unsub?.() }) }, From e2fbd098d2a8bf4a468fd1884fc9b90519337983 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 15 Dec 2025 22:57:48 -0500 Subject: [PATCH 025/463] tui: fix dialog select items taking up 2 lines when truncated Prevents text wrapping in dialog select options by removing wrapMode, ensuring truncated text stays on single line and maintains proper timestamp visibility --- packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 3f49a7c32..8e9c17f70 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -307,10 +307,9 @@ function Option(props: { fg={props.active ? fg : props.current ? theme.primary : theme.text} attributes={props.active ? TextAttributes.BOLD : undefined} overflow="hidden" - wrapMode="word" paddingLeft={3} > - {Locale.truncate(props.title, 62)} + {Locale.truncate(props.title, 61)} {props.description} From d7b5b431d67a9ab2183082ce8621cf7bfbcf444b Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Mon, 15 Dec 2025 22:11:30 -0600 Subject: [PATCH 026/463] ci: Update issue assignment and labeling guidelines Clarified assignment responsibilities and labeling for issues related to OpenCode tools. --- .opencode/tool/github-triage.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.opencode/tool/github-triage.txt b/.opencode/tool/github-triage.txt index 78b78a7ce..0c1473a93 100644 --- a/.opencode/tool/github-triage.txt +++ b/.opencode/tool/github-triage.txt @@ -31,6 +31,7 @@ This relates to OpenCode server primarily but has overlap with just about anythi Adam is responsible for managing the Desktop/Web app. If there is an issue relating to the desktop app or `opencode web` command. Assign him. + ### fwang Frank is responsible for managing Zen, if you see complaints about OpenCode Zen, maybe it's the dashboard, the model quality, billing issues, etc. Assign him to the issue. @@ -47,6 +48,8 @@ Sebastian is responsible for managing an OpenTUI (a library for building termina - general terminal stuff Then assign the issue to Him. +(anything that should have opentui label basically) + ### rekram1-node Assign Aiden to an issue as a catch all, if you can't assign anyone else. Most of the time this will be bugs/polish things. @@ -68,7 +71,7 @@ Anything related to slow performance, high ram, high cpu usage, or any other per ### web -Anything related to `opencode web` or the desktop app should have a web label +Anything related to `opencode web` or the desktop app should have a web label. Never add this label for anything terminal/tui related ### zen From ae3990a55756912ef815767673d1e040623a77bc Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 15 Dec 2025 23:07:55 -0600 Subject: [PATCH 027/463] chore: centralize dep to catalog & fix typos --- .github/workflows/triage.yml | 6 ++++-- .opencode/bun.lock | 6 +++--- .opencode/package.json | 2 +- .opencode/tool/github-triage.txt | 4 +--- bun.lock | 5 +++-- github/package.json | 2 +- package.json | 1 + packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- 9 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 2900137f0..9cc76973d 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -24,9 +24,11 @@ jobs: OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} + ISSUE_TITLE: ${{ github.event.issue.title }} + ISSUE_BODY: ${{ github.event.issue.body }} run: | opencode run --agent triage "The following issue was just opened, triage it: - Title: ${{ github.event.issue.title }} + Title: $ISSUE_TITLE - ${{ github.event.issue.body }}" + $ISSUE_BODY" diff --git a/.opencode/bun.lock b/.opencode/bun.lock index cbc88dbe6..6b926ef90 100644 --- a/.opencode/bun.lock +++ b/.opencode/bun.lock @@ -5,7 +5,7 @@ "": { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160036", + "@opencode-ai/plugin": "0.0.0-dev-202512160412", }, }, }, @@ -34,9 +34,9 @@ "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160036", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160036", "zod": "4.1.8" } }, "sha512-6FVQIsC4myRGtH5b80BG2122EDFNDh0TaLfiSl5frssEPGfR/Sny54ZUB0dy9tbqYD8sVA34z2lb34dsyyFfmg=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160412", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160412", "zod": "4.1.8" } }, "sha512-/SGOQeHtRqg89KcAO7iF5b7CTDpCxbMtzXU0BbFzrhF7r7RE+8VCUoHrFKJyS0x6kkDodBajjKIL61yECKW9Ng=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160036", "", {}, "sha512-OHQjEZcBLUPIIxtb2RyTRedTw8FaiQwTRopAzOPocHLDiij9E5rco99LflYX8OuBMJQaH/1YTilVs6ZErTsuIQ=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160412", "", {}, "sha512-NWjoJmxiS/WPU+HR2C6+08EoCwhqjLgGQeEK+oDAZL2TL5OnETyAMG0zlGYxtwqQpRrr9t3rW0MWzC+VYpygFw=="], "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], diff --git a/.opencode/package.json b/.opencode/package.json index d98a0245d..662ee6b16 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160036" + "@opencode-ai/plugin": "0.0.0-dev-202512160412" } } diff --git a/.opencode/tool/github-triage.txt b/.opencode/tool/github-triage.txt index 0c1473a93..14844a19f 100644 --- a/.opencode/tool/github-triage.txt +++ b/.opencode/tool/github-triage.txt @@ -42,14 +42,12 @@ Jay is responsible for documentation. If there is an issue relating to documenta ### kommander -Sebastian is responsible for managing an OpenTUI (a library for building terminal user interfaces). OpenCode's TUI is built with OpenTUI. If there are issues abou: +Sebastian is responsible for managing an OpenTUI (a library for building terminal user interfaces). OpenCode's TUI is built with OpenTUI. If there are issues about: - random characters on screen - keybinds not working on different terminals - general terminal stuff Then assign the issue to Him. -(anything that should have opentui label basically) - ### rekram1-node Assign Aiden to an issue as a catch all, if you can't assign anyone else. Most of the time this will be bugs/polish things. diff --git a/bun.lock b/bun.lock index 3c48017fc..90450d399 100644 --- a/bun.lock +++ b/bun.lock @@ -202,7 +202,7 @@ "version": "1.0.162", "dependencies": { "@octokit/auth-app": "8.0.1", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "hono": "catalog:", "jose": "6.0.11", }, @@ -238,7 +238,7 @@ "@hono/zod-validator": "catalog:", "@modelcontextprotocol/sdk": "1.15.1", "@octokit/graphql": "9.0.2", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "@openauthjs/openauth": "catalog:", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", @@ -470,6 +470,7 @@ "@cloudflare/workers-types": "4.20251008.0", "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", + "@octokit/rest": "22.0.0", "@openauthjs/openauth": "0.0.0-20250322224806", "@pierre/diffs": "1.0.0-beta.3", "@solidjs/meta": "0.29.4", diff --git a/github/package.json b/github/package.json index 1a6598d6b..4d447716f 100644 --- a/github/package.json +++ b/github/package.json @@ -13,7 +13,7 @@ "@actions/core": "1.11.1", "@actions/github": "6.0.1", "@octokit/graphql": "9.0.1", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "@opencode-ai/sdk": "workspace:*" } } diff --git a/package.json b/package.json index 65ecdfdb5..2be8bfe76 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ ], "catalog": { "@types/bun": "1.3.4", + "@octokit/rest": "22.0.0", "@hono/zod-validator": "0.4.2", "ulid": "3.0.1", "@kobalte/core": "0.13.11", diff --git a/packages/function/package.json b/packages/function/package.json index 6e02eb9ea..f1c3cf78a 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@octokit/auth-app": "8.0.1", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "hono": "catalog:", "jose": "6.0.11" } diff --git a/packages/opencode/package.json b/packages/opencode/package.json index cc5e45db8..a3798c4ba 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -64,7 +64,7 @@ "@hono/zod-validator": "catalog:", "@modelcontextprotocol/sdk": "1.15.1", "@octokit/graphql": "9.0.2", - "@octokit/rest": "22.0.0", + "@octokit/rest": "catalog:", "@openauthjs/openauth": "catalog:", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", From 62f080b0e45194b7930eedb1e52675fdb72c9809 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 00:20:05 -0600 Subject: [PATCH 028/463] fix: small bug w/ install script --- .opencode/bun.lock | 6 +++--- .opencode/package.json | 2 +- install | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.opencode/bun.lock b/.opencode/bun.lock index 6b926ef90..f152a1646 100644 --- a/.opencode/bun.lock +++ b/.opencode/bun.lock @@ -5,7 +5,7 @@ "": { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160412", + "@opencode-ai/plugin": "0.0.0-dev-202512160508", }, }, }, @@ -34,9 +34,9 @@ "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160412", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160412", "zod": "4.1.8" } }, "sha512-/SGOQeHtRqg89KcAO7iF5b7CTDpCxbMtzXU0BbFzrhF7r7RE+8VCUoHrFKJyS0x6kkDodBajjKIL61yECKW9Ng=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160508", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160508", "zod": "4.1.8" } }, "sha512-GLnvMQhEWRHG9E84FyyQKPKi54bGUkytXPfZYjwNy9W6djw8zAW/kpeYPrdIJHPdTHk4OjIHEwoB1SXZzGaLFQ=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160412", "", {}, "sha512-NWjoJmxiS/WPU+HR2C6+08EoCwhqjLgGQeEK+oDAZL2TL5OnETyAMG0zlGYxtwqQpRrr9t3rW0MWzC+VYpygFw=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160508", "", {}, "sha512-ICpZ1bX528yQKqYGGyUJQMu3RY0F1pQ6RCoTJ4ESLiYmcXUY1EldgIidiwPA+A/zpEXLu2lPwPZ1LYn/bX6aFA=="], "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], diff --git a/.opencode/package.json b/.opencode/package.json index 662ee6b16..88fd8e891 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160412" + "@opencode-ai/plugin": "0.0.0-dev-202512160508" } } diff --git a/install b/install index 115ac169a..67690b9a3 100755 --- a/install +++ b/install @@ -243,8 +243,8 @@ download_and_install() { local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" mkdir -p "$tmp_dir" - if [[ "$os" == "windows" ]] || ! download_with_progress "$url" "$tmp_dir/$filename"; then - # Fallback to standard curl on Windows or if custom progress fails + if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then + # Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails curl -# -L -o "$tmp_dir/$filename" "$url" fi From 87efd274593c1e104f839e5e103d39dcd39f341e Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Tue, 16 Dec 2025 18:33:04 +0800 Subject: [PATCH 029/463] tauri: macos-only app menu --- packages/tauri/scripts/predev.ts | 1 - packages/tauri/src/index.tsx | 8 ++- packages/tauri/src/menu.ts | 94 ++++++++++++++++++++++++++++++++ packages/tauri/src/updater.ts | 2 + 4 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 packages/tauri/src/menu.ts diff --git a/packages/tauri/scripts/predev.ts b/packages/tauri/scripts/predev.ts index 6b69a3ae5..218215197 100644 --- a/packages/tauri/scripts/predev.ts +++ b/packages/tauri/scripts/predev.ts @@ -1,4 +1,3 @@ -import * as fs from "node:fs/promises" import { $ } from "bun" import { copyBinaryToSidecarFolder, getCurrentSidecar } from "./utils" diff --git a/packages/tauri/src/index.tsx b/packages/tauri/src/index.tsx index 84ba73c07..f3c329b34 100644 --- a/packages/tauri/src/index.tsx +++ b/packages/tauri/src/index.tsx @@ -1,12 +1,14 @@ // @refresh reload import { render } from "solid-js/web" import { App, PlatformProvider, Platform } from "@opencode-ai/desktop" -import { runUpdater } from "./updater" import { onMount } from "solid-js" import { open, save } from "@tauri-apps/plugin-dialog" import { open as shellOpen } from "@tauri-apps/plugin-shell" import { type as ostype } from "@tauri-apps/plugin-os" +import { runUpdater, UPDATER_ENABLED } from "./updater" +import { createMenu } from "./menu" + const root = document.getElementById("root") if (import.meta.env.DEV && !(root instanceof HTMLElement)) { throw new Error( @@ -48,9 +50,11 @@ const platform: Platform = { }, } +createMenu() + render(() => { onMount(() => { - if (window.__OPENCODE__?.updaterEnabled) runUpdater() + if (UPDATER_ENABLED) runUpdater() }) return ( diff --git a/packages/tauri/src/menu.ts b/packages/tauri/src/menu.ts new file mode 100644 index 000000000..72ba9b754 --- /dev/null +++ b/packages/tauri/src/menu.ts @@ -0,0 +1,94 @@ +import { Menu, MenuItem, PredefinedMenuItem, Submenu } from "@tauri-apps/api/menu" +import { type as ostype } from "@tauri-apps/plugin-os" + +import { runUpdater, UPDATER_ENABLED } from "./updater" + +export async function createMenu() { + if (ostype() !== "macos") return; + + const menu = await Menu.new({ + items: [ + await Submenu.new({ + text: "OpenCode", + items: [ + await PredefinedMenuItem.new({ + item: { About: null }, + }), + await MenuItem.new({ + enabled: UPDATER_ENABLED, + action: () => runUpdater(), + text: "Check For Updates...", + }), + await PredefinedMenuItem.new({ + item: "Separator", + }), + await PredefinedMenuItem.new({ + item: "Hide", + }), + await PredefinedMenuItem.new({ + item: "HideOthers", + }), + await PredefinedMenuItem.new({ + item: "ShowAll", + }), + await PredefinedMenuItem.new({ + item: "Separator", + }), + await PredefinedMenuItem.new({ + item: "Quit", + }), + ].filter(Boolean), + }), + // await Submenu.new({ + // text: "File", + // items: [ + // await MenuItem.new({ + // enabled: false, + // text: "Open Project...", + // }), + // await PredefinedMenuItem.new({ + // item: "Separator" + // }), + // await MenuItem.new({ + // enabled: false, + // text: "New Session", + // }), + // await PredefinedMenuItem.new({ + // item: "Separator" + // }), + // await MenuItem.new({ + // enabled: false, + // text: "Close Project", + // }) + // ] + // }), + await Submenu.new({ + text: "Edit", + items: [ + await PredefinedMenuItem.new({ + item: "Undo", + }), + await PredefinedMenuItem.new({ + item: "Redo", + }), + await PredefinedMenuItem.new({ + item: "Separator", + }), + await PredefinedMenuItem.new({ + item: "Cut", + }), + await PredefinedMenuItem.new({ + item: "Copy", + }), + await PredefinedMenuItem.new({ + item: "Paste", + }), + await PredefinedMenuItem.new({ + item: "SelectAll", + }), + ], + }), + ], + }) + menu.setAsAppMenu() +} diff --git a/packages/tauri/src/updater.ts b/packages/tauri/src/updater.ts index 0d3737d1e..d62aae424 100644 --- a/packages/tauri/src/updater.ts +++ b/packages/tauri/src/updater.ts @@ -2,6 +2,8 @@ import { check, DownloadEvent } from "@tauri-apps/plugin-updater" import { relaunch } from "@tauri-apps/plugin-process" import { ask, message } from "@tauri-apps/plugin-dialog" +export const UPDATER_ENABLED = window.__OPENCODE__?.updaterEnabled ?? false + export async function runUpdater(onDownloadEvent?: (progress: DownloadEvent) => void) { let update try { From 75e5130cf8f58b32ee3f3ba2249d5917e7e3d6fc Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 16 Dec 2025 10:33:49 +0000 Subject: [PATCH 030/463] chore: format code --- packages/tauri/src/menu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tauri/src/menu.ts b/packages/tauri/src/menu.ts index 72ba9b754..d32506d32 100644 --- a/packages/tauri/src/menu.ts +++ b/packages/tauri/src/menu.ts @@ -4,7 +4,7 @@ import { type as ostype } from "@tauri-apps/plugin-os" import { runUpdater, UPDATER_ENABLED } from "./updater" export async function createMenu() { - if (ostype() !== "macos") return; + if (ostype() !== "macos") return const menu = await Menu.new({ items: [ From 2330ec6dc3000ae8b86810e9d59b414ad4f05f47 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 16 Dec 2025 10:54:50 +0000 Subject: [PATCH 031/463] fix: font size updates --- packages/desktop/src/pages/layout.tsx | 6 +++--- packages/ui/src/components/message-part.css | 7 ++++--- packages/ui/src/components/session-turn.css | 13 +++++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 965ade9f8..7560e43e6 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -505,7 +505,7 @@ export default function Layout(props: ParentProps) {
From 3f4d1121a4fd5dfd13264b5d9fc1a83953d69e00 Mon Sep 17 00:00:00 2001 From: jinzhongjia Date: Wed, 17 Dec 2025 01:29:06 +0800 Subject: [PATCH 049/463] docs: Add new project entry for opencode.nvim frontend (#5626) --- packages/web/src/content/docs/ecosystem.mdx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/web/src/content/docs/ecosystem.mdx b/packages/web/src/content/docs/ecosystem.mdx index 8f75f5aeb..ce7517d30 100644 --- a/packages/web/src/content/docs/ecosystem.mdx +++ b/packages/web/src/content/docs/ecosystem.mdx @@ -35,12 +35,13 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw ## Projects -| Name | Description | -| ---------------------------------------------------------------------------------- | ---------------------------------------------------------- | -| [kimaki](https://github.com/remorses/kimaki) | Discord bot to control OpenCode sessions, built on the SDK | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim plugin for editor-aware prompts, built on the API | -| [portal](https://github.com/hosenur/portal) | Mobile-first web UI for OpenCode over Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins | +| Name | Description | +| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | Discord bot to control OpenCode sessions, built on the SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim plugin for editor-aware prompts, built on the API | +| [portal](https://github.com/hosenur/portal) | Mobile-first web UI for OpenCode over Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Neovim frontend for opencode - a terminal-based AI coding agent | --- From b78e2db0136f0b883b35c94b56a05c1216070a42 Mon Sep 17 00:00:00 2001 From: shekohex Date: Tue, 16 Dec 2025 19:29:31 +0200 Subject: [PATCH 050/463] docs: fix typo in Google Antigravity github link (#5625) --- packages/web/src/content/docs/ecosystem.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/content/docs/ecosystem.mdx b/packages/web/src/content/docs/ecosystem.mdx index ce7517d30..50a0b3165 100644 --- a/packages/web/src/content/docs/ecosystem.mdx +++ b/packages/web/src/content/docs/ecosystem.mdx @@ -23,7 +23,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw | [opencode-openai-codex-auth](https://github.com/numman-ali/opencode-openai-codex-auth) | Use your ChatGPT Plus/Pro subscription instead of API credits | | [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) | Use your existing Gemini plan instead of API billing | | [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) | Use Antigravity's free models instead of API billing | -| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-goggle-antigravity-auth) | Google Antigravity OAuth Plugin, with support for Google Search, and more robust API handling | +| [opencode-google-antigravity-auth](https://github.com/shekohex/opencode-google-antigravity-auth) | Google Antigravity OAuth Plugin, with support for Google Search, and more robust API handling | | [opencode-dynamic-context-pruning](https://github.com/Tarquinen/opencode-dynamic-context-pruning) | Optimize token usage by pruning obsolete tool outputs | | [opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited.git) | Add native websearch support for supported providers with Google grounded style | | [opencode-pty](https://github.com/shekohex/opencode-pty.git) | Enables AI agents to run background processes in a PTY, send interactive input to them. | From 5be4bda90f16c3489500cb91c03f94ad90dee9a1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 16 Dec 2025 17:30:08 +0000 Subject: [PATCH 051/463] chore: format code --- packages/web/src/content/docs/ecosystem.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/web/src/content/docs/ecosystem.mdx b/packages/web/src/content/docs/ecosystem.mdx index 50a0b3165..d3a7b2c3e 100644 --- a/packages/web/src/content/docs/ecosystem.mdx +++ b/packages/web/src/content/docs/ecosystem.mdx @@ -35,13 +35,13 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw ## Projects -| Name | Description | -| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -| [kimaki](https://github.com/remorses/kimaki) | Discord bot to control OpenCode sessions, built on the SDK | -| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim plugin for editor-aware prompts, built on the API | -| [portal](https://github.com/hosenur/portal) | Mobile-first web UI for OpenCode over Tailscale/VPN | -| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins | -| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Neovim frontend for opencode - a terminal-based AI coding agent | +| Name | Description | +| ---------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| [kimaki](https://github.com/remorses/kimaki) | Discord bot to control OpenCode sessions, built on the SDK | +| [opencode.nvim](https://github.com/NickvanDyke/opencode.nvim) | Neovim plugin for editor-aware prompts, built on the API | +| [portal](https://github.com/hosenur/portal) | Mobile-first web UI for OpenCode over Tailscale/VPN | +| [opencode plugin template](https://github.com/zenobi-us/opencode-plugin-template/) | Template for building OpenCode plugins | +| [opencode.nvim](https://github.com/sudo-tee/opencode.nvim) | Neovim frontend for opencode - a terminal-based AI coding agent | --- From c2944024a84da85d66c7ed01998e6d9b309f6715 Mon Sep 17 00:00:00 2001 From: Fran Zekan Date: Tue, 16 Dec 2025 18:32:31 +0100 Subject: [PATCH 052/463] fix: enable shell alias expansion in ! command (#5621) --- packages/opencode/src/session/prompt.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 251a416cb..3be4c45fd 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1097,7 +1097,7 @@ export namespace SessionPrompt { ` [[ -f ~/.zshenv ]] && source ~/.zshenv >/dev/null 2>&1 || true [[ -f "\${ZDOTDIR:-$HOME}/.zshrc" ]] && source "\${ZDOTDIR:-$HOME}/.zshrc" >/dev/null 2>&1 || true - ${input.command} + eval ${JSON.stringify(input.command)} `, ], }, @@ -1106,8 +1106,9 @@ export namespace SessionPrompt { "-c", "-l", ` + shopt -s expand_aliases [[ -f ~/.bashrc ]] && source ~/.bashrc >/dev/null 2>&1 || true - ${input.command} + eval ${JSON.stringify(input.command)} `, ], }, From 0af2254856de13fe2d7e023ed4f8d16f5201abd9 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 16 Dec 2025 17:34:41 +0000 Subject: [PATCH 053/463] wip: add active state to open select --- packages/ui/src/components/select.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/ui/src/components/select.css b/packages/ui/src/components/select.css index 53d0e4169..e6fd03f27 100644 --- a/packages/ui/src/components/select.css +++ b/packages/ui/src/components/select.css @@ -15,6 +15,18 @@ color: var(--text-weak); transition: transform 0.1s ease-in-out; } + + &[data-expanded] { + &[data-variant="secondary"] { + background-color: var(--button-secondary-hover); + } + &[data-variant="ghost"] { + background-color: var(--surface-raised-base-active); + } + &[data-variant="primary"] { + background-color: var(--icon-strong-active); + } + } } } From 96b9ff8d0ea7a6d8c0790e793ea2ee700a435792 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 16 Dec 2025 17:41:56 +0000 Subject: [PATCH 054/463] fix: remove the selected state from button when select deselected --- packages/ui/src/components/select.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/ui/src/components/select.css b/packages/ui/src/components/select.css index e6fd03f27..63221b85e 100644 --- a/packages/ui/src/components/select.css +++ b/packages/ui/src/components/select.css @@ -27,6 +27,18 @@ background-color: var(--icon-strong-active); } } + + &:not([data-expanded]):focus { + &[data-variant="secondary"] { + background-color: var(--button-secondary-base); + } + &[data-variant="ghost"] { + background-color: transparent; + } + &[data-variant="primary"] { + background-color: var(--icon-strong-base); + } + } } } From 83bcb9e95bcbdd8f4f9e53a0d8fa44f3f51b6c6e Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 13:37:22 -0500 Subject: [PATCH 055/463] tui: fix autocomplete file loading and update dependencies --- .opencode/bun.lock | 6 +-- .opencode/package.json | 2 +- bun.lock | 43 ++++++++++++++++--- package.json | 1 + .../cmd/tui/component/prompt/autocomplete.tsx | 2 +- packages/tauri/src-tauri/src/lib.rs | 19 ++++++++ 6 files changed, 61 insertions(+), 12 deletions(-) diff --git a/.opencode/bun.lock b/.opencode/bun.lock index 40e7c71af..7add90d06 100644 --- a/.opencode/bun.lock +++ b/.opencode/bun.lock @@ -5,7 +5,7 @@ "": { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512161610", + "@opencode-ai/plugin": "0.0.0-dev-202512160327", }, }, }, @@ -34,9 +34,9 @@ "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512161610", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512161610", "zod": "4.1.8" } }, "sha512-5TDOK75WgWeS/Lul+6OkDT0ESYAFhemCD67OjFcNCONpVgicqoiAgDunmQ2TpsZ+bl0S5kxw4wFGKkFjzBIZ2g=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160327", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160327", "zod": "4.1.8" } }, "sha512-KuT7prfGEFa3No6dHWQ1PhClJt2X+GvYPRDpSTcFhPueQ/KvWjHV7kr1pXdtHDEhae3zz/OF5qQujNUUqKjplw=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512161610", "", {}, "sha512-bnAwQ4DNdHqSoqMJfnZbH16qp0WnFSJpYWTmOdr/9hRu5SDjdmPx/QUlZGBg0yovuHJXqd1Fb/FLgljZ9QqGRA=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160327", "", {}, "sha512-towhYrsC5z4mOox+LkiKGTCy62aY/7zlx3s9NR0nbGQQZfAq/KysKt8yHRlcKlE1IYrequKvmHVyzrSEsXbsWA=="], "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], diff --git a/.opencode/package.json b/.opencode/package.json index 78c21b45f..8c1441ef9 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512161610" + "@opencode-ai/plugin": "0.0.0-dev-202512160327" } } diff --git a/bun.lock b/bun.lock index 0ad9b90f7..b30f89dd3 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "opencode", "dependencies": { "@aws-sdk/client-s3": "3.933.0", + "@octokit/rest": "22.0.1", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", "typescript": "catalog:", @@ -1097,11 +1098,11 @@ "@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="], - "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.2.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="], + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@14.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw=="], "@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], - "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.1.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg=="], + "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@17.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw=="], "@octokit/plugin-retry": ["@octokit/plugin-retry@3.0.9", "", { "dependencies": { "@octokit/types": "^6.0.3", "bottleneck": "^2.15.3" } }, "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ=="], @@ -1109,7 +1110,7 @@ "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - "@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="], + "@octokit/rest": ["@octokit/rest@22.0.1", "", { "dependencies": { "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0" } }, "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw=="], "@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="], @@ -4081,9 +4082,9 @@ "@octokit/oauth-methods/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], "@octokit/plugin-retry/@octokit/types": ["@octokit/types@6.41.0", "", { "dependencies": { "@octokit/openapi-types": "^12.11.0" } }, "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="], @@ -4095,6 +4096,8 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@opencode-ai/function/@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="], + "@opencode-ai/tauri/typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], @@ -4287,6 +4290,8 @@ "opencode/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.27", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.17" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bpYruxVLhrTbVH6CCq48zMJNeHu6FmHtEedl9FXckEgcIEAi036idFhJlcRwC1jNCwlacbzb8dPD7OAH1EKJaQ=="], + "opencode/@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="], + "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], "opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], @@ -4645,9 +4650,9 @@ "@octokit/oauth-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], "@octokit/plugin-retry/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@12.11.0", "", {}, "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="], @@ -4655,6 +4660,10 @@ "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + "@opencode-ai/function/@octokit/rest/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.2.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="], + + "@opencode-ai/function/@octokit/rest/@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.1.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg=="], + "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], @@ -4869,6 +4878,10 @@ "opencode/@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.17", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw=="], + "opencode/@octokit/rest/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.2.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="], + + "opencode/@octokit/rest/@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.1.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg=="], + "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], @@ -5025,6 +5038,10 @@ "@modelcontextprotocol/sdk/raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "@opencode-ai/function/@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + + "@opencode-ai/function/@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], @@ -5045,6 +5062,10 @@ "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "opencode/@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + + "opencode/@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], @@ -5139,10 +5160,18 @@ "@jsx-email/cli/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "@opencode-ai/function/@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + + "@opencode-ai/function/@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="], "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], + "opencode/@octokit/rest/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + + "opencode/@octokit/rest/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "opencontrol/@modelcontextprotocol/sdk/express/body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], diff --git a/package.json b/package.json index 2be8bfe76..86f1aca39 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "3.933.0", + "@octokit/rest": "22.0.1", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", "typescript": "catalog:" diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 6fde66944..36e191e1a 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -357,7 +357,7 @@ export function Autocomplete(props: { const options = createMemo(() => { const mixed: AutocompleteOption[] = ( - store.visible === "@" ? [...agents(), ...(files.loading ? files.latest || [] : files())] : [...commands()] + store.visible === "@" ? [...agents(), ...(files() || [])] : [...commands()] ).filter((x) => x.disabled !== true) const currentFilter = filter() if (!currentFilter) return mixed.slice(0, 10) diff --git a/packages/tauri/src-tauri/src/lib.rs b/packages/tauri/src-tauri/src/lib.rs index 02730281f..e06eff7fc 100644 --- a/packages/tauri/src-tauri/src/lib.rs +++ b/packages/tauri/src-tauri/src/lib.rs @@ -49,7 +49,12 @@ fn get_sidecar_port() -> u16 { }) } +fn get_user_shell() -> String { + std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string()) +} + fn spawn_sidecar(app: &AppHandle, port: u16) -> CommandChild { + #[cfg(target_os = "windows")] let (mut rx, child) = app .shell() .sidecar("opencode-cli") @@ -60,6 +65,20 @@ fn spawn_sidecar(app: &AppHandle, port: u16) -> CommandChild { .spawn() .expect("Failed to spawn opencode"); + #[cfg(not(target_os = "windows"))] + let (mut rx, child) = { + let sidecar = app.shell().sidecar("opencode-cli").unwrap(); + let sidecar_path = sidecar.get_program().to_string_lossy(); + let shell = get_user_shell(); + app.shell() + .command(&shell) + .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") + .env("OPENCODE_CLIENT", "desktop") + .args(["-l", "-c", &format!("{} serve --port={}", sidecar_path, port)]) + .spawn() + .expect("Failed to spawn opencode") + }; + tauri::async_runtime::spawn(async move { while let Some(event) = rx.recv().await { match event { From 8c9f6b1d3e077f983b1409bfec49a89dff17619b Mon Sep 17 00:00:00 2001 From: Github Action Date: Tue, 16 Dec 2025 18:38:59 +0000 Subject: [PATCH 056/463] Update Nix flake.lock and hashes --- flake.lock | 6 +++--- nix/hashes.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 580e0af73..458f20dc7 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1765772535, - "narHash": "sha256-aq+dQoaPONOSjtFIBnAXseDm9TUhIbe215TPmkfMYww=", + "lastModified": 1765803225, + "narHash": "sha256-xwaZV/UgJ04+ixbZZfoDE8IsOWjtvQZICh9aamzPnrg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "09b8fda8959d761445f12b55f380d90375a1d6bb", + "rev": "ac9a217389ee622d4e1e727c4efcc9c4bc9089ba", "type": "github" }, "original": { diff --git a/nix/hashes.json b/nix/hashes.json index 4db956bb3..d4ea58177 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,3 +1,3 @@ { - "nodeModules": "sha256-PyoVOza+3WnwZbtpPF6uSN1zkyLsSG2VsgBfIMvIFAs=" + "nodeModules": "sha256-IkvFO/dANwC8MCOW8PqILqyxCa4IDiFZIIM3B4GMB+Q=" } From 79599f351e143e88ec0b95424364021ad6752496 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 13:52:40 -0500 Subject: [PATCH 057/463] chore: update opencode plugin dependencies and fix tauri sidecar path --- .opencode/bun.lock | 6 +++--- .opencode/package.json | 2 +- packages/tauri/src-tauri/src/lib.rs | 13 ++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.opencode/bun.lock b/.opencode/bun.lock index 7add90d06..c5da73870 100644 --- a/.opencode/bun.lock +++ b/.opencode/bun.lock @@ -5,7 +5,7 @@ "": { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160327", + "@opencode-ai/plugin": "1.0.161", }, }, }, @@ -34,9 +34,9 @@ "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512160327", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512160327", "zod": "4.1.8" } }, "sha512-KuT7prfGEFa3No6dHWQ1PhClJt2X+GvYPRDpSTcFhPueQ/KvWjHV7kr1pXdtHDEhae3zz/OF5qQujNUUqKjplw=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@1.0.161", "", { "dependencies": { "@opencode-ai/sdk": "1.0.161", "zod": "4.1.8" } }, "sha512-8bD/SvqO0LMrhPx8rNTF02nUWNW0ajYkuO9uTMnCCqiyWMx7QLcGfM1xMb/qm1gUiWR9KsSFsAr3s5cGkA78yQ=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512160327", "", {}, "sha512-towhYrsC5z4mOox+LkiKGTCy62aY/7zlx3s9NR0nbGQQZfAq/KysKt8yHRlcKlE1IYrequKvmHVyzrSEsXbsWA=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.161", "", {}, "sha512-yhduFCmayZ0C7GKecwZ1fvtixReC3wHM4FOgRTc4ai9nwd7jiGCtFi/pimc/0/6DV4lVkNyp0/2jdMekAZnt7A=="], "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], diff --git a/.opencode/package.json b/.opencode/package.json index 8c1441ef9..59598c25e 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512160327" + "@opencode-ai/plugin": "1.0.161" } } diff --git a/packages/tauri/src-tauri/src/lib.rs b/packages/tauri/src-tauri/src/lib.rs index e06eff7fc..c35137043 100644 --- a/packages/tauri/src-tauri/src/lib.rs +++ b/packages/tauri/src-tauri/src/lib.rs @@ -67,14 +67,21 @@ fn spawn_sidecar(app: &AppHandle, port: u16) -> CommandChild { #[cfg(not(target_os = "windows"))] let (mut rx, child) = { - let sidecar = app.shell().sidecar("opencode-cli").unwrap(); - let sidecar_path = sidecar.get_program().to_string_lossy(); + let sidecar_path = tauri::utils::platform::current_exe() + .expect("Failed to get current exe") + .parent() + .expect("Failed to get parent dir") + .join("opencode-cli"); let shell = get_user_shell(); app.shell() .command(&shell) .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") .env("OPENCODE_CLIENT", "desktop") - .args(["-l", "-c", &format!("{} serve --port={}", sidecar_path, port)]) + .args([ + "-l", + "-c", + &format!("{} serve --port={}", sidecar_path.display(), port), + ]) .spawn() .expect("Failed to spawn opencode") }; From ebefb26e8f7abe2de27e3ece95e425c12d55c62d Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:02:04 -0600 Subject: [PATCH 058/463] chore: cleanup --- packages/desktop/src/context/global-sync.tsx | 1 - packages/desktop/src/context/notification.tsx | 6 ------ 2 files changed, 7 deletions(-) diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/desktop/src/context/global-sync.tsx index ad3a3bf18..7d8186a68 100644 --- a/packages/desktop/src/context/global-sync.tsx +++ b/packages/desktop/src/context/global-sync.tsx @@ -138,7 +138,6 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple } globalSDK.event.listen((e) => { - console.log(e) const directory = e.name const event = e.details diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index ee15bc34a..4c1a39fb2 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -45,13 +45,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi }, ) - // onMount(() => { - // const daysToKeep = 7 - // // setStore("list", (n) => n.filter((n) => !n.viewed && n.time + 1000 * 60 * 60 * 24 * daysToKeep < Date.now())) - // }) - globalSDK.event.listen((e) => { - console.log(e) const directory = e.name const event = e.details const base = { From ff690350b1ac5ec4f415d9d3eabaeb839196fa1c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:49:22 -0600 Subject: [PATCH 059/463] feat(desktop): show write tool output --- packages/desktop/src/app.tsx | 74 +-- packages/desktop/src/pages/session.tsx | 7 +- .../enterprise/src/routes/share/[shareID].tsx | 447 +++++++++--------- packages/ui/src/components/message-part.tsx | 31 +- packages/ui/src/context/code.tsx | 10 + packages/ui/src/context/diff.tsx | 19 +- 6 files changed, 311 insertions(+), 277 deletions(-) create mode 100644 packages/ui/src/context/code.tsx diff --git a/packages/desktop/src/app.tsx b/packages/desktop/src/app.tsx index 789a8fa2d..be31a594e 100644 --- a/packages/desktop/src/app.tsx +++ b/packages/desktop/src/app.tsx @@ -5,7 +5,9 @@ import { MetaProvider } from "@solidjs/meta" import { Font } from "@opencode-ai/ui/font" import { MarkedProvider } from "@opencode-ai/ui/context/marked" import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" +import { CodeComponentProvider } from "@opencode-ai/ui/context/code" import { Diff } from "@opencode-ai/ui/diff" +import { Code } from "@opencode-ai/ui/code" import { GlobalSyncProvider } from "@/context/global-sync" import { LayoutProvider } from "@/context/layout" import { GlobalSDKProvider } from "@/context/global-sdk" @@ -39,41 +41,43 @@ export function App() { - - - - - - - ( - - {props.children} - - )} - > - - - } /> - ( - - - - - - - - )} - /> - - - - - - - + + + + + + + + ( + + {props.children} + + )} + > + + + } /> + ( + + + + + + + + )} + /> + + + + + + + + diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 390872d36..1b23ad5f2 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -1,4 +1,5 @@ import { For, onCleanup, onMount, Show, Match, Switch, createResource, createMemo, createEffect, on } from "solid-js" +import { Dynamic } from "solid-js/web" import { useLocal, type LocalFile } from "@/context/local" import { createStore } from "solid-js/store" import { PromptInput } from "@/components/prompt-input" @@ -11,7 +12,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { ProgressCircle } from "@opencode-ai/ui/progress-circle" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Tabs } from "@opencode-ai/ui/tabs" -import { Code } from "@opencode-ai/ui/code" +import { useCodeComponent } from "@opencode-ai/ui/context/code" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { SessionMessageRail } from "@opencode-ai/ui/session-message-rail" import { SessionReview } from "@opencode-ai/ui/session-review" @@ -48,6 +49,7 @@ export default function Page() { const sync = useSync() const terminal = useTerminal() const dialog = useDialog() + const codeComponent = useCodeComponent() const command = useCommand() const params = useParams() const navigate = useNavigate() @@ -764,7 +766,8 @@ export default function Page() { {(f) => ( - import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) +const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) const SessionDataMissingError = NamedError.create( "SessionDataMissingError", @@ -196,239 +198,254 @@ export default function () { - - {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) => a.time.created - b.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) + + + {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) => a.time.created - b.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 = () => ( -
-
-
- -
v{info().version}
-
-
- -
{model()?.name ?? modelID()}
-
-
- {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
-
-
{info().title}
-
- ) - - const turns = () => ( -
-
{title()}
-
- - {(message) => ( - ( +
+
+
+ +
v{info().version}
+
+
+ - )} - -
-
- -
-
- ) - - const wide = createMemo(() => diffs().length === 0) - - return ( -
-
-
- - - +
{model()?.name ?? modelID()}
+
+
+ {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} +
-
- - +
{info().title}
+
+ ) + + const turns = () => ( +
+
{title()}
+
+ + {(message) => ( + + )} +
- -
-
+
+ +
+
+ ) + + const wide = createMemo(() => diffs().length === 0) + + return ( +
+
+
+ + + +
+
+ + +
+
+
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()} -
-
- - 1 - ? "pr-6 pl-18" - : "px-6"), +
1, + "px-6": !wide() && messages().length === 1, }} > -
- -
- -
-
- 0}> - -
- -
+
+ + 1 + ? "pr-6 pl-18" + : "px-6"), + }} + > +
+ +
+
-
-
-
- - 0}> - - - - Session - - - {diffs().length} Files Changed - - - - {turns()} - - - - - -
- {turns()}
-
-
+ 0}> + +
+ +
+
+
+
+ + 0}> + + + + Session + + + {diffs().length} Files Changed + + + + {turns()} + + + + + +
+ {turns()} +
+
+
+
-
- ) - })} - + ) + })} + + ) diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 33b519ea4..b838bebc2 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -11,6 +11,7 @@ import { } from "@opencode-ai/sdk/v2" import { useData } from "../context" import { useDiffComponent } from "../context/diff" +import { useCodeComponent } from "../context/code" import { BasicTool } from "./basic-tool" import { GenericTool } from "./basic-tool" import { Card } from "./card" @@ -19,6 +20,7 @@ import { Checkbox } from "./checkbox" import { DiffChanges } from "./diff-changes" import { Markdown } from "./markdown" import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path" +import { checksum } from "@opencode-ai/util/encode" export interface MessageProps { message: MessageType @@ -488,9 +490,10 @@ ToolRegistry.register({ ToolRegistry.register({ name: "write", render(props) { - console.log(props) + const codeComponent = useCodeComponent() return ( @@ -507,19 +510,19 @@ ToolRegistry.register({
} > - {/* */} - {/*
*/} - {/* */} - {/*
*/} - {/*
*/} + +
+ +
+
) }, diff --git a/packages/ui/src/context/code.tsx b/packages/ui/src/context/code.tsx new file mode 100644 index 000000000..3a2511527 --- /dev/null +++ b/packages/ui/src/context/code.tsx @@ -0,0 +1,10 @@ +import type { ValidComponent } from "solid-js" +import { createSimpleContext } from "./helper" + +const ctx = createSimpleContext({ + name: "CodeComponent", + init: (props) => props.component, +}) + +export const CodeComponentProvider = ctx.provider +export const useCodeComponent = ctx.use diff --git a/packages/ui/src/context/diff.tsx b/packages/ui/src/context/diff.tsx index 630437de6..747de9cc8 100644 --- a/packages/ui/src/context/diff.tsx +++ b/packages/ui/src/context/diff.tsx @@ -1,13 +1,10 @@ -import { createContext, useContext, type ParentProps, type ValidComponent } from "solid-js" +import type { ValidComponent } from "solid-js" +import { createSimpleContext } from "./helper" -const DiffComponentContext = createContext() +const ctx = createSimpleContext({ + name: "DiffComponent", + init: (props) => props.component, +}) -export function DiffComponentProvider(props: ParentProps<{ component: ValidComponent }>) { - return {props.children} -} - -export function useDiffComponent() { - const component = useContext(DiffComponentContext) - if (!component) throw new Error("DiffComponentProvider must be used to provide a diff component") - return component -} +export const DiffComponentProvider = ctx.provider +export const useDiffComponent = ctx.use From 20e3a74badabc07cb23223c8d8d2bc7052b31a39 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:25:15 -0600 Subject: [PATCH 060/463] fix: defensive audio init --- packages/desktop/src/context/notification.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index 4c1a39fb2..d2c5bae4c 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -31,8 +31,16 @@ export type Notification = TurnCompleteNotification | ErrorNotification export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({ name: "Notification", init: () => { - const idlePlayer = makeAudioPlayer(idleSound) - const errorPlayer = makeAudioPlayer(errorSound) + let idlePlayer: ReturnType | undefined + let errorPlayer: ReturnType | undefined + + try { + idlePlayer = makeAudioPlayer(idleSound) + errorPlayer = makeAudioPlayer(errorSound) + } catch (err) { + console.log("Failed to load audio", err) + } + const globalSDK = useGlobalSDK() const globalSync = useGlobalSync() @@ -60,7 +68,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const match = Binary.search(syncStore.session, sessionID, (s) => s.id) const isChild = match.found && syncStore.session[match.index].parentID if (isChild) break - idlePlayer.play() + idlePlayer?.play() setStore("list", store.list.length, { ...base, type: "turn-complete", @@ -76,7 +84,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const isChild = match.found && syncStore.session[match.index].parentID if (isChild) break } - errorPlayer.play() + errorPlayer?.play() setStore("list", store.list.length, { ...base, type: "error", From 89219a77f717826578703dbd23b7d302696144f5 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:47:18 -0600 Subject: [PATCH 061/463] fix: layout badness --- packages/ui/src/components/session-turn.css | 5 +++-- packages/ui/src/components/session-turn.tsx | 13 ++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index 4b8a44723..5f95b2c30 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -27,7 +27,8 @@ align-items: flex-start; align-self: stretch; min-width: 0; - gap: clamp(8px, calc(42px - var(--scroll-y) * 0.48), 42px); + gap: 42px; + /* gap: clamp(8px, calc(42px - var(--scroll-y) * 0.48), 42px); */ overflow-anchor: none; } @@ -59,7 +60,7 @@ } [data-slot="session-turn-message-content"] { - margin-top: -24px; + margin-top: -18px; } [data-slot="session-turn-message-title"] { diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 0f5a26a2a..5bf3c0bbd 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -57,17 +57,12 @@ export function SessionTurn( userScrolled: false, stickyHeaderHeight: 0, scrollY: 0, - autoScrolling: false, }) function handleScroll() { if (!scrollRef) return - if (state.autoScrolling) return const { scrollTop, scrollHeight, clientHeight } = scrollRef - const scrollRoom = scrollHeight - clientHeight - if (scrollRoom > 100) { - setState("scrollY", scrollTop) - } + setState("scrollY", scrollTop) const atBottom = scrollHeight - scrollTop - clientHeight < 50 if (!atBottom && working()) { setState("userScrolled", true) @@ -81,13 +76,9 @@ export function SessionTurn( } function scrollToBottom() { - if (!scrollRef || state.userScrolled || !working() || state.autoScrolling) return - setState("autoScrolling", true) + if (!scrollRef || state.userScrolled || !working()) return requestAnimationFrame(() => { scrollRef?.scrollTo({ top: scrollRef.scrollHeight, behavior: "instant" }) - requestAnimationFrame(() => { - setState("autoScrolling", false) - }) }) } From 28aba35ff9b1d1fe58da24735a51299ffe1f65d0 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:19:32 -0600 Subject: [PATCH 062/463] feat(desktop): show retries --- packages/desktop/src/pages/layout.tsx | 10 ++--- packages/ui/src/components/session-turn.css | 14 +++++++ packages/ui/src/components/session-turn.tsx | 46 +++++++++++++++++++-- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 79470cf14..6cf7a2b0e 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -413,11 +413,11 @@ export default function Layout(props: ParentProps) { const updated = createMemo(() => DateTime.fromMillis(props.session.time.updated)) const notifications = createMemo(() => notification.session.unseen(props.session.id)) const hasError = createMemo(() => notifications().some((n) => n.type === "error")) - const isWorking = createMemo( - () => - props.session.id !== params.id && - globalSync.child(props.project.worktree)[0].session_status[props.session.id]?.type === "busy", - ) + const isWorking = createMemo(() => { + if (props.session.id === params.id) return false + const status = globalSync.child(props.project.worktree)[0].session_status[props.session.id] + return status?.type === "busy" || status?.type === "retry" + }) return ( <>
status()?.type !== "idle") + const retry = createMemo(() => { + const s = status() + if (s.type !== "retry") return + return s + }) + const [retrySeconds, setRetrySeconds] = createSignal(0) + + createEffect(() => { + const r = retry() + if (!r) { + setRetrySeconds(0) + return + } + + const updateSeconds = () => { + const next = r.next + if (next) setRetrySeconds(Math.max(0, Math.round((next - Date.now()) / 1000))) + } + updateSeconds() + + const timer = setInterval(updateSeconds, 1000) + onCleanup(() => clearInterval(timer)) + }) let scrollRef: HTMLDivElement | undefined const [state, setState] = createStore({ @@ -300,10 +323,12 @@ export function SessionTurn( {/* Trigger (sticky) */}
setState("stickyTriggerRef", el)} data-slot="session-turn-response-trigger">
{/* Response */} - + 0}>
{(assistantMessage) => { From 2b7e2edee55ccb4d7bef0ba167864db399b29b20 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 14:21:07 -0500 Subject: [PATCH 063/463] core: ensure desktop app loads user shell environment variables Changes shell spawn flags from -l to -il so that ~/.zshrc and ~/.bashrc are sourced when starting the desktop app on macOS and Linux. This fixes missing PATH and other environment variables that users expect to be available. --- packages/tauri/src-tauri/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tauri/src-tauri/src/lib.rs b/packages/tauri/src-tauri/src/lib.rs index c35137043..08bec528d 100644 --- a/packages/tauri/src-tauri/src/lib.rs +++ b/packages/tauri/src-tauri/src/lib.rs @@ -78,7 +78,7 @@ fn spawn_sidecar(app: &AppHandle, port: u16) -> CommandChild { .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") .env("OPENCODE_CLIENT", "desktop") .args([ - "-l", + "-il", "-c", &format!("{} serve --port={}", sidecar_path.display(), port), ]) From 77b2331428a91c798b28412457be136f44f5bf96 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 14:21:16 -0500 Subject: [PATCH 064/463] ignore: update opencode plugin dependency --- .opencode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.opencode/package.json b/.opencode/package.json index 59598c25e..ce3c865af 100644 --- a/.opencode/package.json +++ b/.opencode/package.json @@ -1,6 +1,6 @@ { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "1.0.161" + "@opencode-ai/plugin": "0.0.0-dev-202512161906" } } From 40d63cd1e32b20279d8292f376606637bdd00aca Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 14:25:12 -0500 Subject: [PATCH 065/463] fix --- .opencode/package.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .opencode/package.json diff --git a/.opencode/package.json b/.opencode/package.json deleted file mode 100644 index ce3c865af..000000000 --- a/.opencode/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "dependencies": { - "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512161906" - } -} From 4e2d1acf7d1570f7d4738c03636be77541e73c14 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 14:45:03 -0500 Subject: [PATCH 066/463] core: fix Tauri desktop app SSE connection timeout - Add heartbeat events to /global/event and /event SSE endpoints - Send server.heartbeat event every 30s to prevent WKWebView 60s timeout - Fixes desktop app disconnecting from global events after 1 minute --- packages/opencode/src/server/server.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index f1d4ecd8d..d30fe63b8 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -139,8 +139,22 @@ export namespace Server { }) } GlobalBus.on("event", handler) + + // Send heartbeat every 30s to prevent WKWebView timeout (60s default) + const heartbeat = setInterval(() => { + stream.writeSSE({ + data: JSON.stringify({ + payload: { + type: "server.heartbeat", + properties: {}, + }, + }), + }) + }, 30000) + await new Promise((resolve) => { stream.onAbort(() => { + clearInterval(heartbeat) GlobalBus.off("event", handler) resolve() log.info("global event disconnected") @@ -2470,8 +2484,20 @@ export namespace Server { stream.close() } }) + + // Send heartbeat every 30s to prevent WKWebView timeout (60s default) + const heartbeat = setInterval(() => { + stream.writeSSE({ + data: JSON.stringify({ + type: "server.heartbeat", + properties: {}, + }), + }) + }, 30000) + await new Promise((resolve) => { stream.onAbort(() => { + clearInterval(heartbeat) unsub() resolve() log.info("event disconnected") From bbd36e844152d202daf55d71d4c065b0e830b5ed Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 15:06:50 -0500 Subject: [PATCH 067/463] core: update plugin dependency and config loading for .opencode directory support --- .opencode/bun.lock | 6 +++--- packages/opencode/src/config/config.ts | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.opencode/bun.lock b/.opencode/bun.lock index c5da73870..98e9c908d 100644 --- a/.opencode/bun.lock +++ b/.opencode/bun.lock @@ -5,7 +5,7 @@ "": { "dependencies": { "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "1.0.161", + "@opencode-ai/plugin": "0.0.0-dev-202512161920", }, }, }, @@ -34,9 +34,9 @@ "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@1.0.161", "", { "dependencies": { "@opencode-ai/sdk": "1.0.161", "zod": "4.1.8" } }, "sha512-8bD/SvqO0LMrhPx8rNTF02nUWNW0ajYkuO9uTMnCCqiyWMx7QLcGfM1xMb/qm1gUiWR9KsSFsAr3s5cGkA78yQ=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512161920", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512161920", "zod": "4.1.8" } }, "sha512-gkjeTGFHsU13N4leq2zaxTJarX3oeg3Dl4swZyJUeY6xcX0S+OP2A+gJRpJFggN8h39ZdjYRmnxdaB1jhYRORg=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.161", "", {}, "sha512-yhduFCmayZ0C7GKecwZ1fvtixReC3wHM4FOgRTc4ai9nwd7jiGCtFi/pimc/0/6DV4lVkNyp0/2jdMekAZnt7A=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512161920", "", {}, "sha512-K8HjAvscC96jyMjtJ5annvkpo6lQM8qpfCsfcUpqnj4ZdRdj0732QGhS1rq6g5nYWCCnHuSZlGeM6YcdQSVlMw=="], "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 9cf3507e1..9086f70ce 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -5,7 +5,7 @@ import os from "os" import z from "zod" import { Filesystem } from "../util/filesystem" import { ModelsDev } from "../provider/models" -import { mergeDeep, pipe } from "remeda" +import { mergeDeep, pipe, unique } from "remeda" import { Global } from "../global" import fs from "fs/promises" import { lazy } from "../util/lazy" @@ -76,6 +76,13 @@ export namespace Config { stop: Instance.worktree, }), )), + ...(await Array.fromAsync( + Filesystem.up({ + targets: [".opencode"], + start: Global.Path.home, + stop: Global.Path.home, + }), + )), ] if (Flag.OPENCODE_CONFIG_DIR) { @@ -84,7 +91,7 @@ export namespace Config { } const promises: Promise[] = [] - for (const dir of directories) { + for (const dir of unique(directories)) { await assertValid(dir) if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) { From ee10d9b898509b3bfb0cb1da62f1a3476d8451a8 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 14:12:50 -0600 Subject: [PATCH 068/463] ci: auto tag github action once a change is shipped for it --- .github/workflows/release-github-action.yml | 29 ++++++++++++ .opencode/bun.lock | 49 --------------------- 2 files changed, 29 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/release-github-action.yml delete mode 100644 .opencode/bun.lock diff --git a/.github/workflows/release-github-action.yml b/.github/workflows/release-github-action.yml new file mode 100644 index 000000000..491f66f6d --- /dev/null +++ b/.github/workflows/release-github-action.yml @@ -0,0 +1,29 @@ +name: release-github-action + +on: + push: + branches: + - main + paths: + - "github/**" + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + +jobs: + release: + runs-on: blacksmith-4vcpu-ubuntu-2404 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: git fetch --force --tags + + - name: Release + run: | + git config --global user.email "opencode@sst.dev" + git config --global user.name "opencode" + ./github/script/release diff --git a/.opencode/bun.lock b/.opencode/bun.lock deleted file mode 100644 index 98e9c908d..000000000 --- a/.opencode/bun.lock +++ /dev/null @@ -1,49 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 0, - "workspaces": { - "": { - "dependencies": { - "@octokit/rest": "^22.0.1", - "@opencode-ai/plugin": "0.0.0-dev-202512161920", - }, - }, - }, - "packages": { - "@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="], - - "@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="], - - "@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="], - - "@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="], - - "@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], - - "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@14.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw=="], - - "@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="], - - "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@17.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw=="], - - "@octokit/request": ["@octokit/request@10.0.7", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA=="], - - "@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="], - - "@octokit/rest": ["@octokit/rest@22.0.1", "", { "dependencies": { "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0" } }, "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw=="], - - "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], - - "@opencode-ai/plugin": ["@opencode-ai/plugin@0.0.0-dev-202512161920", "", { "dependencies": { "@opencode-ai/sdk": "0.0.0-dev-202512161920", "zod": "4.1.8" } }, "sha512-gkjeTGFHsU13N4leq2zaxTJarX3oeg3Dl4swZyJUeY6xcX0S+OP2A+gJRpJFggN8h39ZdjYRmnxdaB1jhYRORg=="], - - "@opencode-ai/sdk": ["@opencode-ai/sdk@0.0.0-dev-202512161920", "", {}, "sha512-K8HjAvscC96jyMjtJ5annvkpo6lQM8qpfCsfcUpqnj4ZdRdj0732QGhS1rq6g5nYWCCnHuSZlGeM6YcdQSVlMw=="], - - "before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], - - "fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="], - - "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], - - "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], - } -} From 87524de26563f67f0627b767d35ab3ae12762ea6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 14:15:50 -0600 Subject: [PATCH 069/463] ci: fix triage --- .github/workflows/triage.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 9cc76973d..6e1509572 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -16,6 +16,9 @@ jobs: with: fetch-depth: 1 + - name: Setup Bun + uses: ./.github/actions/setup-bun + - name: Install opencode run: curl -fsSL https://opencode.ai/install | bash From 7e3ad770ac340da1589da1d6a9f182e56e3da619 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 14:31:09 -0600 Subject: [PATCH 070/463] fix: git branch filewatcher, add flag to completely disable watcher --- packages/opencode/src/file/watcher.ts | 28 +++++++++++++++++++-------- packages/opencode/src/flag/flag.ts | 2 ++ packages/web/src/content/docs/cli.mdx | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index 80e524349..50a310d96 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -5,11 +5,13 @@ import { Instance } from "../project/instance" import { Log } from "../util/log" import { FileIgnore } from "./ignore" import { Config } from "../config/config" +import path from "path" // @ts-ignore import { createWrapper } from "@parcel/watcher/wrapper" import { lazy } from "@/util/lazy" import type ParcelWatcher from "@parcel/watcher" import { $ } from "bun" +import { Flag } from "@/flag/flag" declare const OPENCODE_LIBC: string | undefined @@ -57,17 +59,24 @@ export namespace FileWatcher { } } - const subs = [] + const subs: ParcelWatcher.AsyncSubscription[] = [] const cfgIgnores = cfg.watcher?.ignore ?? [] - subs.push( - await watcher().subscribe(Instance.directory, subscribe, { - ignore: [...FileIgnore.PATTERNS, ...cfgIgnores], - backend, - }), - ) + if (Flag.OPENCODE_EXPERIMENTAL_FILEWATCHER) { + subs.push( + await watcher().subscribe(Instance.directory, subscribe, { + ignore: [...FileIgnore.PATTERNS, ...cfgIgnores], + backend, + }), + ) + } - const vcsDir = await $`git rev-parse --git-dir`.quiet().nothrow().cwd(Instance.worktree).text() + const vcsDir = await $`git rev-parse --git-dir` + .quiet() + .nothrow() + .cwd(Instance.worktree) + .text() + .then((x) => path.resolve(Instance.worktree, x.trim())) if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir)) { subs.push( await watcher().subscribe(vcsDir, subscribe, { @@ -86,6 +95,9 @@ export namespace FileWatcher { ) export function init() { + if (Flag.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER) { + return + } state() } } diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index d7a24708a..544188d4e 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -17,6 +17,8 @@ export namespace Flag { // Experimental export const OPENCODE_EXPERIMENTAL = truthy("OPENCODE_EXPERIMENTAL") + export const OPENCODE_EXPERIMENTAL_FILEWATCHER = truthy("OPENCODE_EXPERIMENTAL_FILEWATCHER") + export const OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = truthy("OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER") export const OPENCODE_EXPERIMENTAL_ICON_DISCOVERY = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY") export const OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT = truthy("OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT") diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 777d377a7..6fd7307b2 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -325,3 +325,4 @@ These environment variables enable experimental features that may change or be r | `OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT` | boolean | Disable copy on select in TUI | | `OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH` | number | Max output length for bash commands | | `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` | number | Default timeout for bash commands in ms | +| `OPENCODE_EXPERIMENTAL_FILEWATCHER` | boolean | Enable file watcher for entire dir | From d556143e3bb0b33ac71d531a9666923fde7280e3 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 14:35:42 -0600 Subject: [PATCH 071/463] ci: fix branch name --- .github/workflows/release-github-action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-github-action.yml b/.github/workflows/release-github-action.yml index 491f66f6d..3f5caa55c 100644 --- a/.github/workflows/release-github-action.yml +++ b/.github/workflows/release-github-action.yml @@ -3,7 +3,7 @@ name: release-github-action on: push: branches: - - main + - dev paths: - "github/**" From 984f17ddd7c420a19f98dae2cd3e8b2173ec52e2 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 14:37:33 -0600 Subject: [PATCH 072/463] ci: include desktop & tauri in release notes --- script/publish.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/publish.ts b/script/publish.ts index 121da8baa..7b5256312 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -17,7 +17,7 @@ if (!Script.preview) { .then((data: any) => data.version) const log = - await $`git log v${previous}..HEAD --oneline --format="%h %s" -- packages/opencode packages/sdk packages/plugin`.text() + await $`git log v${previous}..HEAD --oneline --format="%h %s" -- packages/opencode packages/sdk packages/plugin packages/tauri packages/desktop`.text() const commits = log .split("\n") From 1aee8b49e1d7158533652fc611fdb811b2ff59fb Mon Sep 17 00:00:00 2001 From: matvey Date: Tue, 16 Dec 2025 23:43:14 +0300 Subject: [PATCH 073/463] feat: add experimental oxfmt formatter (#5620) --- packages/opencode/src/flag/flag.ts | 1 + packages/opencode/src/format/formatter.ts | 20 ++++++++++ packages/web/src/content/docs/cli.mdx | 1 + packages/web/src/content/docs/formatters.mdx | 39 ++++++++++---------- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 544188d4e..b49d19615 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -26,6 +26,7 @@ export namespace Flag { truthy("OPENCODE_ENABLE_EXA") || OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_EXA") export const OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH = number("OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH") export const OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS = number("OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS") + export const OPENCODE_EXPERIMENTAL_OXFMT = OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_OXFMT") function truthy(key: string) { const value = process.env[key]?.toLowerCase() diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index c4e7c9ee8..954940f8d 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -2,6 +2,7 @@ import { readableStreamToText } from "bun" import { BunProc } from "../bun" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" +import { Flag } from "@/flag/flag" export interface Info { name: string @@ -74,6 +75,25 @@ export const prettier: Info = { }, } +export const oxfmt: Info = { + name: "oxfmt", + command: [BunProc.which(), "x", "oxfmt", "$FILE"], + environment: { + BUN_BE_BUN: "1", + }, + extensions: [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"], + async enabled() { + if (!Flag.OPENCODE_EXPERIMENTAL_OXFMT) return false + const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree) + for (const item of items) { + const json = await Bun.file(item).json() + if (json.dependencies?.oxfmt) return true + if (json.devDependencies?.oxfmt) return true + } + return false + }, +} + export const biome: Info = { name: "biome", command: [BunProc.which(), "x", "@biomejs/biome", "format", "--write", "$FILE"], diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 6fd7307b2..393046c97 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -326,3 +326,4 @@ These environment variables enable experimental features that may change or be r | `OPENCODE_EXPERIMENTAL_BASH_MAX_OUTPUT_LENGTH` | number | Max output length for bash commands | | `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` | number | Default timeout for bash commands in ms | | `OPENCODE_EXPERIMENTAL_FILEWATCHER` | boolean | Enable file watcher for entire dir | +| `OPENCODE_EXPERIMENTAL_OXFMT` | boolean | Enable oxfmt formatter | diff --git a/packages/web/src/content/docs/formatters.mdx b/packages/web/src/content/docs/formatters.mdx index 052138f68..c2c01836b 100644 --- a/packages/web/src/content/docs/formatters.mdx +++ b/packages/web/src/content/docs/formatters.mdx @@ -11,25 +11,26 @@ OpenCode automatically formats files after they are written or edited using lang OpenCode comes with several built-in formatters for popular languages and frameworks. Below is a list of the formatters, supported file extensions, and commands or config options it needs. -| Formatter | Extensions | Requirements | -| -------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | -| gofmt | .go | `gofmt` command available | -| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available | -| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` | -| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json(c)` config file | -| zig | .zig, .zon | `zig` command available | -| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | -| ktlint | .kt, .kts | `ktlint` command available | -| ruff | .py, .pyi | `ruff` command available with config | -| uv | .py, .pyi | `uv` command available | -| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | -| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | -| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | -| air | .R | `air` command available | -| dart | .dart | `dart` command available | -| ocamlformat | .ml, .mli | `ocamlformat` command available and `.ocamlformat` config file | -| terraform | .tf, .tfvars | `terraform` command available | -| gleam | .gleam | `gleam` command available | +| Formatter | Extensions | Requirements | +| -------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| gofmt | .go | `gofmt` command available | +| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` command available | +| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://prettier.io/docs/en/index.html) | `prettier` dependency in `package.json` | +| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml, and [more](https://biomejs.dev/) | `biome.json(c)` config file | +| zig | .zig, .zon | `zig` command available | +| clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | +| ktlint | .kt, .kts | `ktlint` command available | +| ruff | .py, .pyi | `ruff` command available with config | +| uv | .py, .pyi | `uv` command available | +| rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | +| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | +| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | +| air | .R | `air` command available | +| dart | .dart | `dart` command available | +| ocamlformat | .ml, .mli | `ocamlformat` command available and `.ocamlformat` config file | +| terraform | .tf, .tfvars | `terraform` command available | +| gleam | .gleam | `gleam` command available | +| oxfmt (Experimental) | .js, .jsx, .ts, .tsx | `oxfmt` dependency in `package.json` and an [experiental env variable flag](/docs/cli/#experimental) | So if your project has `prettier` in your `package.json`, OpenCode will automatically use it. From a2c91ebc32dba43004aba31adad2b54efcf1b34a Mon Sep 17 00:00:00 2001 From: Eric Guo Date: Wed, 17 Dec 2025 04:50:33 +0800 Subject: [PATCH 074/463] feat(desktop): Loading more session number per project by button (#5616) Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> --- packages/desktop/src/context/global-sync.tsx | 6 +++--- packages/desktop/src/pages/layout.tsx | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/desktop/src/context/global-sync.tsx index 7d8186a68..53b891065 100644 --- a/packages/desktop/src/context/global-sync.tsx +++ b/packages/desktop/src/context/global-sync.tsx @@ -99,19 +99,19 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple } async function loadSessions(directory: string) { + const [store, setStore] = child(directory) globalSDK.client.session.list({ directory }).then((x) => { const fourHoursAgo = Date.now() - 4 * 60 * 60 * 1000 const nonArchived = (x.data ?? []) .slice() .filter((s) => !s.time.archived) .sort((a, b) => a.id.localeCompare(b.id)) - // Include at least 5 sessions, plus any updated in the last hour + // Include sessions up to the limit, plus any updated in the last hour const sessions = nonArchived.filter((s, i) => { - if (i < 5) return true + if (i < store.limit) return true const updated = new Date(s.time.updated).getTime() return updated > fourHoursAgo }) - const [, setStore] = child(directory) setStore("session", sessions) }) } diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 6cf7a2b0e..aba435332 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -497,7 +497,7 @@ export default function Layout(props: ParentProps) { const sortable = createSortable(props.project.worktree) const slug = createMemo(() => base64Encode(props.project.worktree)) const name = createMemo(() => getFilename(props.project.worktree)) - const [store] = globalSync.child(props.project.worktree) + const [store, setProjectStore] = globalSync.child(props.project.worktree) const sessions = createMemo(() => store.session ?? []) const rootSessions = createMemo(() => sessions().filter((s) => !s.parentID)) const childSessionsByParent = createMemo(() => { @@ -511,6 +511,11 @@ export default function Layout(props: ParentProps) { } return map }) + const hasMoreSessions = createMemo(() => store.session.length >= store.limit) + const loadMoreSessions = async () => { + setProjectStore("limit", (limit) => limit + 10) + await globalSync.project.loadSessions(props.project.worktree) + } const [expanded, setExpanded] = createSignal(true) return ( // @ts-ignore @@ -583,6 +588,19 @@ export default function Layout(props: ParentProps) {
+ +
+ +
+
From 5eeba76bc52668e7d184249d5a2fbd7ad36c8ea7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:34:22 -0600 Subject: [PATCH 075/463] fix: defensive audio init --- packages/desktop/src/context/notification.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/context/notification.tsx b/packages/desktop/src/context/notification.tsx index d2c5bae4c..5ca813448 100644 --- a/packages/desktop/src/context/notification.tsx +++ b/packages/desktop/src/context/notification.tsx @@ -68,7 +68,9 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const match = Binary.search(syncStore.session, sessionID, (s) => s.id) const isChild = match.found && syncStore.session[match.index].parentID if (isChild) break - idlePlayer?.play() + try { + idlePlayer?.play() + } catch {} setStore("list", store.list.length, { ...base, type: "turn-complete", @@ -84,7 +86,9 @@ export const { use: useNotification, provider: NotificationProvider } = createSi const isChild = match.found && syncStore.session[match.index].parentID if (isChild) break } - errorPlayer?.play() + try { + errorPlayer?.play() + } catch {} setStore("list", store.list.length, { ...base, type: "error", From 7e682a95c4c77ba187b07a90d8ed2eac5238d06b Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:46:07 -0600 Subject: [PATCH 076/463] fix: prompt input multi line input --- .../desktop/src/components/prompt-input.tsx | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 6e147242d..6bd3127be 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -380,31 +380,47 @@ export const PromptInput: Component = (props) => { const parseFromDOM = (): Prompt => { const newParts: Prompt = [] let position = 0 - editorRef.childNodes.forEach((node) => { - if (node.nodeType === Node.TEXT_NODE) { - if (node.textContent) { - const content = node.textContent - newParts.push({ type: "text", content, start: position, end: position + content.length }) - position += content.length - } - } else if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).dataset.type) { - switch ((node as HTMLElement).dataset.type) { - case "file": - const content = node.textContent! - newParts.push({ - type: "file", - path: (node as HTMLElement).dataset.path!, - content, - start: position, - end: position + content.length, - }) - position += content.length - break - default: - break - } - } + + const pushText = (content: string) => { + if (!content) return + newParts.push({ type: "text", content, start: position, end: position + content.length }) + position += content.length + } + + const rangeText = (range: Range) => { + const fragment = range.cloneContents() + const container = document.createElement("div") + container.append(fragment) + return container.innerText + } + + const files = Array.from(editorRef.querySelectorAll("[data-type=file]")) + let last: HTMLElement | undefined + + files.forEach((file) => { + const before = document.createRange() + before.selectNodeContents(editorRef) + if (last) before.setStartAfter(last) + before.setEndBefore(file) + pushText(rangeText(before)) + + const content = file.textContent ?? "" + newParts.push({ + type: "file", + path: file.dataset.path!, + content, + start: position, + end: position + content.length, + }) + position += content.length + last = file }) + + const after = document.createRange() + after.selectNodeContents(editorRef) + if (last) after.setStartAfter(last) + pushText(rangeText(after)) + if (newParts.length === 0) newParts.push(...DEFAULT_PROMPT) return newParts } From 96e4dcb521ed6c1d42ce31e1a603abd0016b39a7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:09:33 -0600 Subject: [PATCH 077/463] fix: working logic --- packages/ui/src/components/session-turn.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index ade9a04ab..213d72160 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -48,7 +48,7 @@ export function SessionTurn( type: "idle", }, ) - const working = createMemo(() => status()?.type !== "idle") + const working = createMemo(() => status()?.type !== "idle" && message()?.id === userMessages().at(-1)?.id) const retry = createMemo(() => { const s = status() if (s.type !== "retry") return @@ -306,7 +306,7 @@ export function SessionTurn(
- + From b4014e5baabfa0a404464cf71c153c8dbbe7ac65 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:39:45 -0600 Subject: [PATCH 078/463] fix: auto-scroll --- packages/ui/src/components/session-turn.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 213d72160..14e4055ca 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -75,6 +75,7 @@ export function SessionTurn( let scrollRef: HTMLDivElement | undefined const [state, setState] = createStore({ + contentRef: undefined as HTMLDivElement | undefined, stickyTitleRef: undefined as HTMLDivElement | undefined, stickyTriggerRef: undefined as HTMLDivElement | undefined, userScrolled: false, @@ -101,10 +102,18 @@ export function SessionTurn( function scrollToBottom() { if (!scrollRef || state.userScrolled || !working()) return requestAnimationFrame(() => { - scrollRef?.scrollTo({ top: scrollRef.scrollHeight, behavior: "instant" }) + scrollRef?.scrollTo({ top: scrollRef.scrollHeight, behavior: "smooth" }) }) } + createResizeObserver( + () => state.contentRef, + ({ height }) => { + console.log(height) + scrollToBottom() + }, + ) + createEffect(() => { if (!working()) { setState("userScrolled", false) @@ -232,11 +241,6 @@ export function SessionTurn( }) } - createEffect(() => { - lastPart() - scrollToBottom() - }) - const [store, setStore] = createStore({ status: rawStatus(), stepsExpanded: props.stepsExpanded ?? working(), @@ -296,6 +300,7 @@ export function SessionTurn( return (
setState("contentRef", el)} data-message={message().id} data-slot="session-turn-message-container" class={props.classes?.container} From 9aa5460a0e1292dbfa6abcf944e8f5982618f3ca Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:10:38 -0600 Subject: [PATCH 079/463] fix(desktop): prompt history navigation --- packages/desktop/src/components/prompt-input.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 6bd3127be..a04211a98 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -593,23 +593,24 @@ export const PromptInput: Component = (props) => { if (event.key === "ArrowUp" || event.key === "ArrowDown") { if (event.altKey || event.ctrlKey || event.metaKey) return - const { collapsed, cursorPosition, textLength } = getCaretState() + const { collapsed } = getCaretState() if (!collapsed) return + + const cursorPosition = getCursorPosition(editorRef) + const textLength = promptLength(prompt.current()) const inHistory = store.historyIndex >= 0 - const atAbsoluteStart = cursorPosition === 0 - const atAbsoluteEnd = cursorPosition === textLength - const allowUp = (inHistory && atAbsoluteEnd) || atAbsoluteStart - const allowDown = (inHistory && atAbsoluteStart) || atAbsoluteEnd + const atStart = cursorPosition <= 0 + const atEnd = cursorPosition >= textLength if (event.key === "ArrowUp") { - if (!allowUp) return + if (!atStart && !(inHistory && atEnd)) return if (navigateHistory("up")) { event.preventDefault() } return } - if (!allowDown) return + if (!atEnd && !(inHistory && atStart)) return if (navigateHistory("down")) { event.preventDefault() } From 99680baf83cd494a97b4db115ba2f1a2a4f7ce06 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:25:00 -0600 Subject: [PATCH 080/463] fix(desktop): focus prompt input after dialog close --- packages/desktop/src/components/prompt-input.tsx | 1 + packages/ui/src/components/session-turn.tsx | 3 +-- packages/ui/src/context/dialog.tsx | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index a04211a98..b152ff0f5 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -850,6 +850,7 @@ export const PromptInput: Component = (props) => {
{ editorRef = el props.ref?.(el) diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 14e4055ca..cab6a7af3 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -108,8 +108,7 @@ export function SessionTurn( createResizeObserver( () => state.contentRef, - ({ height }) => { - console.log(height) + () => { scrollToBottom() }, ) diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx index 71fc63806..56be9ee47 100644 --- a/packages/ui/src/context/dialog.tsx +++ b/packages/ui/src/context/dialog.tsx @@ -33,6 +33,10 @@ function init() { }, close() { active()?.onClose?.() + if (!active()?.onClose) { + const promptInput = document.querySelector("[data-component=prompt-input]") as HTMLElement + promptInput?.focus() + } setActive(undefined) }, show(element: DialogElement, owner: Owner, onClose?: () => void) { @@ -48,7 +52,6 @@ function init() { open={true} onOpenChange={(open) => { if (!open) { - console.log("closing") result.close() } }} From 1755a3fe0778ca9021fe7b59218c1830826502bc Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:32:14 -0600 Subject: [PATCH 081/463] fix(desktop): auto-scroll --- packages/ui/src/components/session-turn.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index cab6a7af3..fa435b402 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -106,12 +106,7 @@ export function SessionTurn( }) } - createResizeObserver( - () => state.contentRef, - () => { - scrollToBottom() - }, - ) + createResizeObserver(() => state.contentRef, scrollToBottom) createEffect(() => { if (!working()) { From 5f57cee8e46abc6b1368c10991a22b2d676cf2a4 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:42:21 -0800 Subject: [PATCH 082/463] =?UTF-8?q?fix:=20user=20invoked=20subtasks=20caus?= =?UTF-8?q?ing=20tool=5Fuse=20or=20missing=20thinking=20signa=E2=80=A6=20(?= =?UTF-8?q?#5650)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .opencode/command/commit.md | 1 + packages/opencode/src/session/prompt.ts | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/.opencode/command/commit.md b/.opencode/command/commit.md index c318ed54b..8e9346ebc 100644 --- a/.opencode/command/commit.md +++ b/.opencode/command/commit.md @@ -1,6 +1,7 @@ --- description: git commit and push model: opencode/glm-4.6 +subtask: true --- commit and push diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 3be4c45fd..4ae7469a3 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -396,6 +396,30 @@ export namespace SessionPrompt { }, } satisfies MessageV2.ToolPart) } + + // Add synthetic user message to prevent certain reasoning models from erroring + // If we create assistant messages w/ out user ones following mid loop thinking signatures + // will be missing and it can cause errors for models like gemini for example + const summaryUserMsg: MessageV2.User = { + id: Identifier.ascending("message"), + sessionID, + role: "user", + time: { + created: Date.now(), + }, + agent: lastUser.agent, + model: lastUser.model, + } + await Session.updateMessage(summaryUserMsg) + await Session.updatePart({ + id: Identifier.ascending("part"), + messageID: summaryUserMsg.id, + sessionID, + type: "text", + text: "Summarize the task tool output above and continue with your task.", + synthetic: true, + } satisfies MessageV2.TextPart) + continue } From f07d4b933c015310bbb7703c02b2672595a2aef6 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:42:31 -0600 Subject: [PATCH 083/463] fix(desktop): prompt history nav --- packages/desktop/src/components/prompt-input.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index b152ff0f5..aea9f4e23 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -598,19 +598,24 @@ export const PromptInput: Component = (props) => { const cursorPosition = getCursorPosition(editorRef) const textLength = promptLength(prompt.current()) + const textContent = editorRef.textContent ?? "" + const isEmpty = textContent.trim() === "" || textLength <= 1 + const hasNewlines = textContent.includes("\n") const inHistory = store.historyIndex >= 0 - const atStart = cursorPosition <= 0 - const atEnd = cursorPosition >= textLength + const atStart = cursorPosition <= (isEmpty ? 1 : 0) + const atEnd = cursorPosition >= (isEmpty ? textLength - 1 : textLength) + const allowUp = isEmpty || atStart || (!hasNewlines && !inHistory) || (inHistory && atEnd) + const allowDown = isEmpty || atEnd || (!hasNewlines && !inHistory) || (inHistory && atStart) if (event.key === "ArrowUp") { - if (!atStart && !(inHistory && atEnd)) return + if (!allowUp) return if (navigateHistory("up")) { event.preventDefault() } return } - if (!atEnd && !(inHistory && atStart)) return + if (!allowDown) return if (navigateHistory("down")) { event.preventDefault() } From ef0fa2007b658ca49d4a19ab4234553b9380ee80 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 16 Dec 2025 21:47:41 +0000 Subject: [PATCH 084/463] release: v1.0.164 --- bun.lock | 30 +++++++++++++------------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/enterprise/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/tauri/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index b30f89dd3..5718408a1 100644 --- a/bun.lock +++ b/bun.lock @@ -21,7 +21,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -49,7 +49,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -76,7 +76,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -100,7 +100,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -124,7 +124,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -171,7 +171,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -200,7 +200,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -216,7 +216,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.163", + "version": "1.0.164", "bin": { "opencode": "./bin/opencode", }, @@ -308,7 +308,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -328,7 +328,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.163", + "version": "1.0.164", "devDependencies": { "@hey-api/openapi-ts": "0.88.1", "@tsconfig/node22": "catalog:", @@ -339,7 +339,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -352,7 +352,7 @@ }, "packages/tauri": { "name": "@opencode-ai/tauri", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@opencode-ai/desktop": "workspace:*", "@tauri-apps/api": "^2", @@ -377,7 +377,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -412,7 +412,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "zod": "catalog:", }, @@ -423,7 +423,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 7607f03a4..ca24a5d26 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.0.163", + "version": "1.0.164", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 7704332a7..b37dc0294 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.163", + "version": "1.0.164", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index e62078f9a..7a88069bb 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.163", + "version": "1.0.164", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 5fc887fe4..6c718fee5 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.163", + "version": "1.0.164", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 026fd4ec4..7f28ecc10 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.163", + "version": "1.0.164", "description": "", "type": "module", "exports": { diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json index 36e8ef01c..edb2fa605 100644 --- a/packages/enterprise/package.json +++ b/packages/enterprise/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/enterprise", - "version": "1.0.163", + "version": "1.0.164", "private": true, "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 8d7a72cb9..9f375b720 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The open source coding agent." -version = "1.0.163" +version = "1.0.164" 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.163/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.164/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.163/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.164/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.163/opencode-linux-arm64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.164/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.163/opencode-linux-x64.tar.gz" +archive = "https://github.com/sst/opencode/releases/download/v1.0.164/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.163/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.164/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 7fdd342ce..95d22ed34 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.163", + "version": "1.0.164", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index d65b1dec2..003c3677c 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.163", + "version": "1.0.164", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index c94dffabe..0febe1a10 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.163", + "version": "1.0.164", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 2ea45ea7b..e596b9d6e 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.163", + "version": "1.0.164", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 07412a5ff..afa90acc3 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.163", + "version": "1.0.164", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index 9568e279d..e0c6b177a 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/tauri", "private": true, - "version": "1.0.163", + "version": "1.0.164", "type": "module", "scripts": { "typecheck": "tsgo -b", diff --git a/packages/ui/package.json b/packages/ui/package.json index 2db6c52a1..b2e7e331d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.163", + "version": "1.0.164", "type": "module", "exports": { "./*": "./src/components/*.tsx", diff --git a/packages/util/package.json b/packages/util/package.json index 8f4a10a8d..59b13aa35 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "1.0.163", + "version": "1.0.164", "private": true, "type": "module", "exports": { diff --git a/packages/web/package.json b/packages/web/package.json index e1a51be71..b7ca5ee89 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.163", + "version": "1.0.164", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 773143ef9..b9f638f4c 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.163", + "version": "1.0.164", "publisher": "sst-dev", "repository": { "type": "git", From 2f2ea989372393620b754604688d791978a7d7e1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:06:28 -0600 Subject: [PATCH 085/463] fix(share): content wasn't centered --- packages/enterprise/src/routes/share/[shareID].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index 236fbf26b..bc3ca9f08 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -352,7 +352,7 @@ export default function () { messageID={store.messageId ?? firstUserMessage()!.id!} classes={{ root: "grow", - content: "flex flex-col justify-between items-start", + content: "flex flex-col justify-between", container: "w-full pb-20 " + (wide() From fc940dfcfb8d265a3cb0f678fa5228fbe6ad61c2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 16 Dec 2025 22:07:10 +0000 Subject: [PATCH 086/463] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 0febe1a10..7ebdcbe1d 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index e596b9d6e..fdae55022 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -29,4 +29,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 29aaf4f0000d4f917557aad590a9cdbc4bf015d5 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 16 Dec 2025 17:17:06 -0500 Subject: [PATCH 087/463] ci: fix release draft configuration to prevent automatic draft flag --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index afc23a81f..6b26e4421 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -211,6 +211,6 @@ jobs: fetch-depth: 0 ref: ${{ needs.publish.outputs.tagName }} - - run: gh release edit ${{ steps.publish.outputs.tagName }} --draft=false + - run: gh release edit ${{ needs.publish.outputs.tagName }} --draft=false env: GH_TOKEN: ${{ github.token }} From 8a185aa67844ca74ef07ed424257f7fbbc55abe6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 16 Dec 2025 16:31:46 -0600 Subject: [PATCH 088/463] ci: fix missing pkg issue --- .github/workflows/duplicate-issues.yml | 2 ++ .github/workflows/review.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/duplicate-issues.yml b/.github/workflows/duplicate-issues.yml index 5969d9d41..dc82d297b 100644 --- a/.github/workflows/duplicate-issues.yml +++ b/.github/workflows/duplicate-issues.yml @@ -16,6 +16,8 @@ jobs: with: fetch-depth: 1 + - uses: ./.github/actions/setup-bun + - name: Install opencode run: curl -fsSL https://opencode.ai/install | bash diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index d974e2a76..36f6df54f 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -29,6 +29,8 @@ jobs: with: fetch-depth: 1 + - uses: ./.github/actions/setup-bun + - name: Install opencode run: curl -fsSL https://opencode.ai/install | bash From a0f9f8dabb42979911107fc3630bda1867549415 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 16 Dec 2025 23:23:18 +0000 Subject: [PATCH 089/463] fix: load more button --- packages/desktop/src/pages/layout.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index aba435332..bed8950c7 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -589,12 +589,11 @@ export default function Layout(props: ParentProps) {
-
+
+ + + + + } + > + {iife(() => { + const [url] = createResource( + () => currentSession(), + async (session) => { + if (!session) return + let shareURL = session.share?.url + if (!shareURL) { + shareURL = await globalSDK.client.session + .share({ sessionID: session.id, directory: currentDirectory() }) + .then((r) => r.data?.share?.url) + } + return shareURL + }, + ) + return {(url) => } + })} + +
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index bed8950c7..618b84840 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -25,9 +25,8 @@ import { SortableProvider, closestCenter, createSortable, - useDragDropContext, } from "@thisbeyond/solid-dnd" -import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" +import type { DragEvent } from "@thisbeyond/solid-dnd" import { useProviders } from "@/hooks/use-providers" import { Toast } from "@opencode-ai/ui/toast" import { useGlobalSDK } from "@/context/global-sdk" @@ -37,6 +36,7 @@ import { Header } from "@/components/header" import { useDialog } from "@opencode-ai/ui/context/dialog" import { DialogSelectProvider } from "@/components/dialog-select-provider" import { useCommand } from "@/context/command" +import { ConstrainDragXAxis } from "@/utils/solid-dnd" export default function Layout(props: ParentProps) { const [store, setStore] = createStore({ @@ -301,28 +301,6 @@ export default function Layout(props: ParentProps) { setStore("activeDraggable", undefined) } - const ConstrainDragXAxis = (): JSX.Element => { - const context = useDragDropContext() - if (!context) return <> - const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context - const transformer: Transformer = { - id: "constrain-x-axis", - order: 100, - callback: (transform) => ({ ...transform, x: 0 }), - } - onDragStart((event) => { - const id = getDraggableId(event) - if (!id) return - addTransformer("draggables", id, transformer) - }) - onDragEnd((event) => { - const id = getDraggableId(event) - if (!id) return - removeTransformer("draggables", id, transformer.id) - }) - return <> - } - const ProjectAvatar = (props: { project: Project class?: string diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index d024d5047..3415d0c4e 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -23,9 +23,8 @@ import { SortableProvider, closestCenter, createSortable, - useDragDropContext, } from "@thisbeyond/solid-dnd" -import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" +import type { DragEvent } from "@thisbeyond/solid-dnd" import type { JSX } from "solid-js" import { useSync } from "@/context/sync" import { useTerminal, type LocalPTY } from "@/context/terminal" @@ -42,6 +41,7 @@ import { AssistantMessage, UserMessage } from "@opencode-ai/sdk/v2" import { useSDK } from "@/context/sdk" import { usePrompt } from "@/context/prompt" import { extractPromptFromParts } from "@/utils/prompt" +import { ConstrainDragYAxis, getDraggableId } from "@/utils/solid-dnd" export default function Page() { const layout = useLayout() @@ -324,19 +324,6 @@ export default function Page() { if ((document.activeElement as HTMLElement)?.dataset?.component === "terminal") return if (dialog.active) return - if (event.key === "PageUp" || event.key === "PageDown") { - const scrollContainer = document.querySelector('[data-slot="session-turn-content"]') as HTMLElement - if (scrollContainer) { - event.preventDefault() - const scrollAmount = scrollContainer.clientHeight * 0.8 - scrollContainer.scrollBy({ - top: event.key === "PageUp" ? -scrollAmount : scrollAmount, - behavior: "instant", - }) - } - return - } - const focused = document.activeElement === inputRef if (focused) { if (event.key === "Escape") inputRef?.blur() @@ -519,36 +506,6 @@ export default function Page() { ) } - const ConstrainDragYAxis = (): JSX.Element => { - const context = useDragDropContext() - if (!context) return <> - const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context - const transformer: Transformer = { - id: "constrain-y-axis", - order: 100, - callback: (transform) => ({ ...transform, y: 0 }), - } - onDragStart((event) => { - const id = getDraggableId(event) - if (!id) return - addTransformer("draggables", id, transformer) - }) - onDragEnd((event) => { - const id = getDraggableId(event) - if (!id) return - removeTransformer("draggables", id, transformer.id) - }) - return <> - } - - const getDraggableId = (event: unknown): string | undefined => { - if (typeof event !== "object" || event === null) return undefined - if (!("draggable" in event)) return undefined - const draggable = (event as { draggable?: { id?: unknown } }).draggable - if (!draggable) return undefined - return typeof draggable.id === "string" ? draggable.id : undefined - } - const wide = createMemo(() => layout.review.state() === "tab" || !diffs().length) return ( diff --git a/packages/desktop/src/utils/solid-dnd.tsx b/packages/desktop/src/utils/solid-dnd.tsx new file mode 100644 index 000000000..a634be4b4 --- /dev/null +++ b/packages/desktop/src/utils/solid-dnd.tsx @@ -0,0 +1,55 @@ +import { useDragDropContext } from "@thisbeyond/solid-dnd" +import { JSXElement } from "solid-js" +import type { Transformer } from "@thisbeyond/solid-dnd" + +export const getDraggableId = (event: unknown): string | undefined => { + if (typeof event !== "object" || event === null) return undefined + if (!("draggable" in event)) return undefined + const draggable = (event as { draggable?: { id?: unknown } }).draggable + if (!draggable) return undefined + return typeof draggable.id === "string" ? draggable.id : undefined +} + +export const ConstrainDragXAxis = (): JSXElement => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-x-axis", + order: 100, + callback: (transform) => ({ ...transform, x: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> +} + +export const ConstrainDragYAxis = (): JSXElement => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-y-axis", + order: 100, + callback: (transform) => ({ ...transform, y: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> +} diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index b8e8106e8..94d9544d6 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -52,6 +52,7 @@ const icons = { copy: ``, check: ``, photo: ``, + share: ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/popover.css b/packages/ui/src/components/popover.css new file mode 100644 index 000000000..74d7f5a39 --- /dev/null +++ b/packages/ui/src/components/popover.css @@ -0,0 +1,95 @@ +[data-slot="popover-trigger"] { + display: inline-flex; +} + +[data-component="popover-content"] { + z-index: 50; + min-width: 200px; + max-width: 320px; + border-radius: var(--radius-md); + border: 1px solid var(--border-weak-base); + background-color: var(--surface-raised-stronger-non-alpha); + box-shadow: var(--shadow-md); + transform-origin: var(--kb-popover-content-transform-origin); + + &:focus-within { + outline: none; + } + + &[data-closed] { + animation: popover-close 0.15s ease-out; + } + + &[data-expanded] { + animation: popover-open 0.15s ease-out; + } + + [data-slot="popover-header"] { + display: flex; + padding: 12px; + padding-bottom: 0; + justify-content: space-between; + align-items: center; + gap: 8px; + + [data-slot="popover-title"] { + flex: 1; + color: var(--text-strong); + margin: 0; + + font-family: var(--font-family-sans); + font-size: var(--font-size-base); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); + letter-spacing: var(--letter-spacing-normal); + } + + [data-slot="popover-close-button"] { + flex-shrink: 0; + } + } + + [data-slot="popover-description"] { + padding: 0 12px; + margin: 0; + color: var(--text-base); + + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: normal; + font-weight: var(--font-weight-regular); + line-height: var(--line-height-large); + letter-spacing: var(--letter-spacing-normal); + } + + [data-slot="popover-body"] { + padding: 12px; + } + + [data-slot="popover-arrow"] { + fill: var(--surface-raised-stronger-non-alpha); + } +} + +@keyframes popover-open { + from { + opacity: 0; + transform: scale(0.96); + } + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes popover-close { + from { + opacity: 1; + transform: scale(1); + } + to { + opacity: 0; + transform: scale(0.96); + } +} diff --git a/packages/ui/src/components/popover.tsx b/packages/ui/src/components/popover.tsx new file mode 100644 index 000000000..3262098e5 --- /dev/null +++ b/packages/ui/src/components/popover.tsx @@ -0,0 +1,44 @@ +import { Popover as Kobalte } from "@kobalte/core/popover" +import { ComponentProps, JSXElement, ParentProps, Show, splitProps } from "solid-js" +import { IconButton } from "./icon-button" + +export interface PopoverProps extends ParentProps, Omit, "children"> { + trigger: JSXElement + title?: JSXElement + description?: JSXElement + class?: ComponentProps<"div">["class"] + classList?: ComponentProps<"div">["classList"] +} + +export function Popover(props: PopoverProps) { + const [local, rest] = splitProps(props, ["trigger", "title", "description", "class", "classList", "children"]) + + return ( + + + {local.trigger} + + + + {/* */} + +
+ {local.title} + +
+
+ + {local.description} + +
{local.children}
+
+
+
+ ) +} diff --git a/packages/ui/src/components/text-field.tsx b/packages/ui/src/components/text-field.tsx index 63ffb2594..77f014b6b 100644 --- a/packages/ui/src/components/text-field.tsx +++ b/packages/ui/src/components/text-field.tsx @@ -56,6 +56,10 @@ export function TextField(props: TextFieldProps) { setTimeout(() => setCopied(false), 2000) } + function handleClick() { + if (local.copyable) handleCopy() + } + return ( ) } - -/** @deprecated Use TextField instead */ -export const Input = TextField -/** @deprecated Use TextFieldProps instead */ -export type InputProps = TextFieldProps diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index 3f8838a7a..c4302a4d3 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -27,6 +27,7 @@ @import "../components/markdown.css" layer(components); @import "../components/message-part.css" layer(components); @import "../components/message-nav.css" layer(components); +@import "../components/popover.css" layer(components); @import "../components/progress-circle.css" layer(components); @import "../components/resize-handle.css" layer(components); @import "../components/select.css" layer(components); From d7e133732cb4378190a68be256ff2a3fc336cff7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 17 Dec 2025 03:58:16 -0600 Subject: [PATCH 102/463] chore: cleanup --- packages/ui/src/components/session-turn.css | 2 -- packages/ui/src/components/session-turn.tsx | 38 ++++++++++----------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index c0408cb0c..3861312cc 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -1,6 +1,5 @@ [data-component="session-turn"] { /* flex: 1; */ - --scroll-y: 0px; height: 100%; min-height: 0; min-width: 0; @@ -28,7 +27,6 @@ align-self: stretch; min-width: 0; gap: 42px; - /* gap: clamp(8px, calc(42px - var(--scroll-y) * 0.48), 42px); */ overflow-anchor: none; } diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index fa435b402..722b02492 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -3,7 +3,7 @@ import { useData } from "../context" import { useDiffComponent } from "../context/diff" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { checksum } from "@opencode-ai/util/encode" -import { createEffect, createMemo, createSignal, For, Match, onCleanup, ParentProps, Show, Switch } from "solid-js" +import { createEffect, createMemo, For, Match, onCleanup, ParentProps, Show, Switch } from "solid-js" import { createResizeObserver } from "@solid-primitives/resize-observer" import { DiffChanges } from "./diff-changes" import { Typewriter } from "./typewriter" @@ -54,18 +54,27 @@ export function SessionTurn( if (s.type !== "retry") return return s }) - const [retrySeconds, setRetrySeconds] = createSignal(0) + + let scrollRef: HTMLDivElement | undefined + const [state, setState] = createStore({ + contentRef: undefined as HTMLDivElement | undefined, + stickyTitleRef: undefined as HTMLDivElement | undefined, + stickyTriggerRef: undefined as HTMLDivElement | undefined, + autoScrolled: false, + userScrolled: false, + stickyHeaderHeight: 0, + retrySeconds: 0, + }) createEffect(() => { const r = retry() if (!r) { - setRetrySeconds(0) + setState("retrySeconds", 0) return } - const updateSeconds = () => { const next = r.next - if (next) setRetrySeconds(Math.max(0, Math.round((next - Date.now()) / 1000))) + if (next) setState("retrySeconds", Math.max(0, Math.round((next - Date.now()) / 1000))) } updateSeconds() @@ -73,20 +82,9 @@ export function SessionTurn( onCleanup(() => clearInterval(timer)) }) - let scrollRef: HTMLDivElement | undefined - const [state, setState] = createStore({ - contentRef: undefined as HTMLDivElement | undefined, - stickyTitleRef: undefined as HTMLDivElement | undefined, - stickyTriggerRef: undefined as HTMLDivElement | undefined, - userScrolled: false, - stickyHeaderHeight: 0, - scrollY: 0, - }) - function handleScroll() { - if (!scrollRef) return + if (!scrollRef || state.autoScrolled) return const { scrollTop, scrollHeight, clientHeight } = scrollRef - setState("scrollY", scrollTop) const atBottom = scrollHeight - scrollTop - clientHeight < 50 if (!atBottom && working()) { setState("userScrolled", true) @@ -101,8 +99,10 @@ export function SessionTurn( function scrollToBottom() { if (!scrollRef || state.userScrolled || !working()) return + setState("autoScrolled", true) requestAnimationFrame(() => { scrollRef?.scrollTo({ top: scrollRef.scrollHeight, behavior: "smooth" }) + setState("autoScrolled", false) }) } @@ -131,7 +131,7 @@ export function SessionTurn( ) return ( -
+
@@ -346,7 +346,7 @@ export function SessionTurn( })()} - · retrying {retrySeconds() > 0 ? `in ${retrySeconds()}s ` : ""} + · retrying {state.retrySeconds > 0 ? `in ${state.retrySeconds}s ` : ""} (#{retry()?.attempt}) From b695d3b6bb4d1f48cfa75ab1c866a42418d9c81b Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 17 Dec 2025 11:21:56 +0000 Subject: [PATCH 103/463] fix: website cta button --- packages/console/app/src/routes/brand/index.css | 5 ++++- packages/console/app/src/routes/enterprise/index.css | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/routes/brand/index.css b/packages/console/app/src/routes/brand/index.css index b7c76f5bb..1240b91a5 100644 --- a/packages/console/app/src/routes/brand/index.css +++ b/packages/console/app/src/routes/brand/index.css @@ -110,10 +110,13 @@ [data-slot="cta-button"] { background: var(--color-background-strong); color: var(--color-text-inverted); - padding: 8px 16px; + padding: 8px 16px 8px 10px; border-radius: 4px; font-weight: 500; text-decoration: none; + display: flex; + align-items: center; + gap: 8px; @media (max-width: 55rem) { display: none; diff --git a/packages/console/app/src/routes/enterprise/index.css b/packages/console/app/src/routes/enterprise/index.css index 496a886eb..7eebf16ce 100644 --- a/packages/console/app/src/routes/enterprise/index.css +++ b/packages/console/app/src/routes/enterprise/index.css @@ -110,10 +110,13 @@ [data-slot="cta-button"] { background: var(--color-background-strong); color: var(--color-text-inverted); - padding: 8px 16px; + padding: 8px 16px 8px 10px; border-radius: 4px; font-weight: 500; text-decoration: none; + display: flex; + align-items: center; + gap: 8px; @media (max-width: 55rem) { display: none; From 4375149e638eb1b0655aa38c4506b196ee11623f Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 17 Dec 2025 11:43:04 +0000 Subject: [PATCH 104/463] wip: auto-detect OS and show desktop download button --- .../console/app/src/routes/download/index.tsx | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/console/app/src/routes/download/index.tsx b/packages/console/app/src/routes/download/index.tsx index 7783a738a..d8d2b5bb0 100644 --- a/packages/console/app/src/routes/download/index.tsx +++ b/packages/console/app/src/routes/download/index.tsx @@ -8,6 +8,47 @@ import { Faq } from "~/component/faq" import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png" import { Legal } from "~/component/legal" import { config } from "~/config" +import { createSignal, onMount, Show, JSX } from "solid-js" + +type OS = "macOS" | "Windows" | "Linux" | null + +function detectOS(): OS { + if (typeof navigator === "undefined") return null + const platform = navigator.platform.toLowerCase() + const userAgent = navigator.userAgent.toLowerCase() + + if (platform.includes("mac") || userAgent.includes("mac")) return "macOS" + if (platform.includes("win") || userAgent.includes("win")) return "Windows" + if (platform.includes("linux") || userAgent.includes("linux")) return "Linux" + return null +} + +function getDownloadUrl(os: OS): string { + const base = "https://github.com/sst/opencode/releases/latest/download" + switch (os) { + case "macOS": + return `${base}/opencode-desktop-darwin-aarch64.dmg` + case "Windows": + return `${base}/opencode-desktop-windows-x64.exe` + case "Linux": + return `${base}/opencode-desktop-linux-amd64.deb` + default: + return `${base}/opencode-desktop-darwin-aarch64.dmg` + } +} + +function IconDownload(props: JSX.SvgSVGAttributes) { + return ( + + + + ) +} function CopyStatus() { return ( @@ -20,6 +61,12 @@ function CopyStatus() { export default function Download() { const downloadUrl = "https://github.com/sst/opencode/releases/latest/download" + const [detectedOS, setDetectedOS] = createSignal(null) + + onMount(() => { + setDetectedOS(detectOS()) + }) + const handleCopyClick = (command: string) => (event: Event) => { const button = event.currentTarget as HTMLButtonElement navigator.clipboard.writeText(command) @@ -44,6 +91,12 @@ export default function Download() {

Download OpenCode

Available in Beta for macOS, Windows, and Linux

+ + + + Download for {detectedOS()} + +
From 5da1c0087b7a0216bf633d12ff038422727ff235 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 17 Dec 2025 12:04:41 +0000 Subject: [PATCH 105/463] ignore: update download stats 2025-12-17 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index c29c4dde9..c08f2e4b7 100644 --- a/STATS.md +++ b/STATS.md @@ -172,3 +172,4 @@ | 2025-12-14 | 1,082,042 (+8,481) | 1,052,425 (+7,817) | 2,134,467 (+16,298) | | 2025-12-15 | 1,093,632 (+11,590) | 1,059,078 (+6,653) | 2,152,710 (+18,243) | | 2025-12-16 | 1,120,477 (+26,845) | 1,078,022 (+18,944) | 2,198,499 (+45,789) | +| 2025-12-17 | 1,151,067 (+30,590) | 1,097,661 (+19,639) | 2,248,728 (+50,229) | From 5c490c51edd5a8e3953fcc439d46c0e138294073 Mon Sep 17 00:00:00 2001 From: Amadeus Demarzi Date: Wed, 17 Dec 2025 05:33:46 -0800 Subject: [PATCH 106/463] Diffs Performance Improvements (#5653) Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> --- packages/desktop/src/pages/layout.tsx | 4 +- packages/desktop/src/pages/session.tsx | 9 +- .../enterprise/src/routes/share/[shareID].tsx | 474 +++++++++--------- packages/ui/package.json | 1 + packages/ui/src/components/diff-ssr.tsx | 23 +- packages/ui/src/components/diff.css | 2 + packages/ui/src/components/session-review.css | 1 + packages/ui/src/context/worker-pool.tsx | 10 + packages/ui/src/custom-elements.d.ts | 5 +- packages/ui/src/pierre/worker.ts | 36 +- 10 files changed, 305 insertions(+), 260 deletions(-) create mode 100644 packages/ui/src/context/worker-pool.tsx diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 618b84840..540c5d778 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -613,7 +613,7 @@ export default function Layout(props: ParentProps) { classList={{ "relative @container w-12 pb-5 shrink-0 bg-background-base": true, "flex flex-col gap-5.5 items-start self-stretch justify-between": true, - "border-r border-border-weak-base": true, + "border-r border-border-weak-base contain-strict": true, }} style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }} > @@ -755,7 +755,7 @@ export default function Layout(props: ParentProps) {
-
{props.children}
+
{props.children}
diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 3415d0c4e..7d1392c20 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -578,7 +578,10 @@ export default function Page() {
- +
- +
import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) +const ClientOnlyWorkerPoolProvider = clientOnly(() => + import("@opencode-ai/ui/pierre/worker").then((m) => ({ + default: (props: { children: any }) => ( + {props.children} + ), + })), +) const SessionDataMissingError = NamedError.create( "SessionDataMissingError", @@ -197,256 +205,260 @@ export default function () { - - - - {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) => a.time.created - b.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) + + + + + {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) => a.time.created - b.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 = () => ( -
-
-
- -
v{info().version}
-
-
- -
{model()?.name ?? modelID()}
-
-
- {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
-
-
{info().title}
-
- ) - - const turns = () => ( -
-
{title()}
-
- - {(message) => ( - ( +
+
+
+ +
v{info().version}
+
+
+ - )} - -
-
- -
-
- ) - - const wide = createMemo(() => diffs().length === 0) - - return ( -
-
-
- - - +
{model()?.name ?? modelID()}
+
+
+ {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} +
-
- - +
{info().title}
+
+ ) + + const turns = () => ( +
+
{title()}
+
+ + {(message) => ( + + )} +
- -
-
+
+ +
+
+ ) + + const wide = createMemo(() => diffs().length === 0) + + return ( +
+
+
+ + + +
+
+ + +
+
+
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-200": !wide(), }} > - {title()} -
-
- - 1 - ? "pr-6 pl-18" - : "px-6"), +
1, + "px-6": !wide() && messages().length === 1, }} > -
- -
- -
-
- 0}> - -
- -
-
-
-
- - 0}> - - - - Session - - + + 1 + ? "pr-6 pl-18" + : "px-6"), + }} > - {diffs().length} Files Changed - - - - {turns()} - - - - - -
- {turns()} +
+ +
+ +
- - + 0}> + +
+ +
+
+
+
+ + 0}> + + + + Session + + + {diffs().length} Files Changed + + + + {turns()} + + + + + +
+ {turns()} +
+
+
+
-
- ) - })} - - - + ) + })} + + + + ) }} diff --git a/packages/ui/package.json b/packages/ui/package.json index b2e7e331d..618dbf1f0 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -5,6 +5,7 @@ "exports": { "./*": "./src/components/*.tsx", "./pierre": "./src/pierre/index.ts", + "./pierre/*": "./src/pierre/*.ts", "./hooks": "./src/hooks/index.ts", "./context": "./src/context/index.ts", "./context/*": "./src/context/*.tsx", diff --git a/packages/ui/src/components/diff-ssr.tsx b/packages/ui/src/components/diff-ssr.tsx index b38b4a34f..e367a4fbe 100644 --- a/packages/ui/src/components/diff-ssr.tsx +++ b/packages/ui/src/components/diff-ssr.tsx @@ -1,8 +1,9 @@ -import { FileDiff } from "@pierre/diffs" +import { DIFFS_TAG_NAME, FileDiff } from "@pierre/diffs" import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" import { onCleanup, onMount, Show, splitProps } from "solid-js" -import { isServer } from "solid-js/web" +import { Dynamic, isServer } from "solid-js/web" import { createDefaultOptions, styleVariables, type DiffProps } from "../pierre" +import { useWorkerPool } from "../context/worker-pool" export type SSRDiffProps = DiffProps & { preloadedDiff: PreloadMultiFileDiffResult @@ -12,17 +13,21 @@ export function Diff(props: SSRDiffProps) { let container!: HTMLDivElement let fileDiffRef!: HTMLElement const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"]) + const workerPool = useWorkerPool() let fileDiffInstance: FileDiff | undefined const cleanupFunctions: Array<() => void> = [] onMount(() => { if (isServer || !props.preloadedDiff) return - fileDiffInstance = new FileDiff({ - ...createDefaultOptions(props.diffStyle), - ...others, - ...props.preloadedDiff, - }) + fileDiffInstance = new FileDiff( + { + ...createDefaultOptions(props.diffStyle), + ...others, + ...props.preloadedDiff, + }, + workerPool, + ) // @ts-expect-error - fileContainer is private but needed for SSR hydration fileDiffInstance.fileContainer = fileDiffRef fileDiffInstance.hydrate({ @@ -65,11 +70,11 @@ export function Diff(props: SSRDiffProps) { return (
- +