From a0611d92e472c4f1b4d66056b86f28f6b58064b1 Mon Sep 17 00:00:00 2001 From: Julian LaNeve Date: Tue, 11 Nov 2025 14:52:45 -0800 Subject: [PATCH 01/20] docs: Update config references to latest Sonnet & Haiku models (#4210) --- packages/web/src/content/docs/config.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index 2a259ff371..c02edd2fff 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -16,7 +16,7 @@ OpenCode supports both **JSON** and **JSONC** (JSON with Comments) formats. "$schema": "https://opencode.ai/config.json", // Theme configuration "theme": "opencode", - "model": "anthropic/claude-sonnet-4-20250514", + "model": "anthropic/claude-sonnet-4-5", "autoupdate": true, } ``` @@ -128,8 +128,8 @@ You can configure the providers and models you want to use in your OpenCode conf { "$schema": "https://opencode.ai/config.json", "provider": {}, - "model": "anthropic/claude-sonnet-4-20250514", - "small_model": "anthropic/claude-3-5-haiku-20241022" + "model": "anthropic/claude-sonnet-4-5", + "small_model": "anthropic/claude-haiku-4-5" } ``` @@ -164,7 +164,7 @@ You can configure specialized agents for specific tasks through the `agent` opti "agent": { "code-reviewer": { "description": "Reviews code for best practices and potential issues", - "model": "anthropic/claude-sonnet-4-20250514", + "model": "anthropic/claude-sonnet-4-5", "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.", "tools": { // Disable file modification tools for review-only agent @@ -213,7 +213,7 @@ You can configure custom commands for repetitive tasks through the `command` opt "template": "Run the full test suite with coverage report and show any failures.\nFocus on the failing tests and suggest fixes.", "description": "Run tests with coverage", "agent": "build", - "model": "anthropic/claude-3-5-sonnet-20241022", + "model": "anthropic/claude-haiku-4-5", }, "component": { "template": "Create a new React component named $ARGUMENTS with TypeScript support.\nInclude proper typing and basic structure.", From f13c17e65424ac45a995b29a1f70ba8d5210ee23 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 11 Nov 2025 18:01:16 -0500 Subject: [PATCH 02/20] wip: poc pr command --- packages/opencode/src/cli/cmd/pr.ts | 85 +++++++++++++++++++++++++++++ packages/opencode/src/index.ts | 2 + 2 files changed, 87 insertions(+) create mode 100644 packages/opencode/src/cli/cmd/pr.ts diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts new file mode 100644 index 0000000000..fb6171a717 --- /dev/null +++ b/packages/opencode/src/cli/cmd/pr.ts @@ -0,0 +1,85 @@ +import { UI } from "../ui" +import { cmd } from "./cmd" +import { Instance } from "@/project/instance" +import { $ } from "bun" + +export const PrCommand = cmd({ + command: "pr ", + describe: "fetch and checkout a GitHub PR branch, then run opencode", + builder: (yargs) => + yargs.positional("number", { + type: "number", + describe: "PR number to checkout", + demandOption: true, + }), + async handler(args) { + await Instance.provide({ + directory: process.cwd(), + async fn() { + const project = Instance.project + if (project.vcs !== "git") { + UI.error("Could not find git repository. Please run this command from a git repository.") + process.exit(1) + } + + const prNumber = args.number + const localBranchName = `pr/${prNumber}` + UI.println(`Fetching and checking out PR #${prNumber}...`) + + // Use gh pr checkout with custom branch name + const result = await $`gh pr checkout ${prNumber} --branch ${localBranchName} --force`.nothrow() + + if (result.exitCode !== 0) { + UI.error(`Failed to checkout PR #${prNumber}. Make sure you have gh CLI installed and authenticated.`) + process.exit(1) + } + + // For fork PRs, add the fork as a remote to enable pushing + const prInfoResult = + await $`gh pr view ${prNumber} --json headRepository,headRepositoryOwner,isCrossRepository,headRefName`.nothrow() + if (prInfoResult.exitCode === 0) { + const prInfoText = prInfoResult.text() + if (prInfoText.trim()) { + const prInfo = JSON.parse(prInfoText) + if (prInfo && prInfo.isCrossRepository && prInfo.headRepository && prInfo.headRepositoryOwner) { + const forkOwner = prInfo.headRepositoryOwner.login + const forkName = prInfo.headRepository.name + const remoteName = forkOwner + + // Check if remote already exists + const remotes = (await $`git remote`.nothrow().text()).trim() + if (!remotes.split("\n").includes(remoteName)) { + await $`git remote add ${remoteName} https://github.com/${forkOwner}/${forkName}.git`.nothrow() + UI.println(`Added fork remote: ${remoteName}`) + } + + // Set upstream to the fork so pushes go there + const headRefName = prInfo.headRefName + await $`git branch --set-upstream-to=${remoteName}/${headRefName} ${localBranchName}`.nothrow() + } + } + } + + UI.println(`Successfully checked out PR #${prNumber} as branch '${localBranchName}'`) + UI.println() + UI.println("Starting opencode...") + UI.println() + + // Launch opencode TUI + const { spawn } = await import("child_process") + const opencodeProcess = spawn("opencode", [], { + stdio: "inherit", + cwd: process.cwd(), + }) + + await new Promise((resolve, reject) => { + opencodeProcess.on("exit", (code) => { + if (code === 0) resolve() + else reject(new Error(`opencode exited with code ${code}`)) + }) + opencodeProcess.on("error", reject) + }) + }, + }) + }, +}) diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 0158069972..acd7ee1c09 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -24,6 +24,7 @@ import { TuiSpawnCommand } from "./cli/cmd/tui/spawn" import { AcpCommand } from "./cli/cmd/acp" import { EOL } from "os" import { WebCommand } from "./cli/cmd/web" +import { PrCommand } from "./cli/cmd/pr" process.on("unhandledRejection", (e) => { Log.Default.error("rejection", { @@ -90,6 +91,7 @@ const cli = yargs(hideBin(process.argv)) .command(ExportCommand) .command(ImportCommand) .command(GithubCommand) + .command(PrCommand) .fail((msg) => { if ( msg.startsWith("Unknown argument") || From 834a2c09d57b39faedb0b3416bc6fa216778637f Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 11 Nov 2025 18:37:38 -0500 Subject: [PATCH 03/20] wip: poc pr command --- packages/opencode/src/cli/cmd/pr.ts | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts index fb6171a717..1bbb9e25d9 100644 --- a/packages/opencode/src/cli/cmd/pr.ts +++ b/packages/opencode/src/cli/cmd/pr.ts @@ -34,13 +34,18 @@ export const PrCommand = cmd({ process.exit(1) } - // For fork PRs, add the fork as a remote to enable pushing + // Fetch PR info for fork handling and session link detection const prInfoResult = - await $`gh pr view ${prNumber} --json headRepository,headRepositoryOwner,isCrossRepository,headRefName`.nothrow() + await $`gh pr view ${prNumber} --json headRepository,headRepositoryOwner,isCrossRepository,headRefName,body`.nothrow() + + let sessionId: string | undefined + if (prInfoResult.exitCode === 0) { const prInfoText = prInfoResult.text() if (prInfoText.trim()) { const prInfo = JSON.parse(prInfoText) + + // Handle fork PRs if (prInfo && prInfo.isCrossRepository && prInfo.headRepository && prInfo.headRepositoryOwner) { const forkOwner = prInfo.headRepositoryOwner.login const forkName = prInfo.headRepository.name @@ -57,6 +62,27 @@ export const PrCommand = cmd({ const headRefName = prInfo.headRefName await $`git branch --set-upstream-to=${remoteName}/${headRefName} ${localBranchName}`.nothrow() } + + // Check for opencode session link in PR body + if (prInfo && prInfo.body) { + const sessionMatch = prInfo.body.match(/https:\/\/opencode\.ai\/s\/([a-zA-Z0-9_-]+)/) + if (sessionMatch) { + const sessionUrl = sessionMatch[0] + UI.println(`Found opencode session: ${sessionUrl}`) + UI.println(`Importing session...`) + + const importResult = await $`opencode import ${sessionUrl}`.nothrow() + if (importResult.exitCode === 0) { + const importOutput = importResult.text().trim() + // Extract session ID from the output (format: "Imported session: ") + const sessionIdMatch = importOutput.match(/Imported session: ([a-zA-Z0-9_-]+)/) + if (sessionIdMatch) { + sessionId = sessionIdMatch[1] + UI.println(`Session imported: ${sessionId}`) + } + } + } + } } } @@ -65,9 +91,10 @@ export const PrCommand = cmd({ UI.println("Starting opencode...") UI.println() - // Launch opencode TUI + // Launch opencode TUI with session ID if available const { spawn } = await import("child_process") - const opencodeProcess = spawn("opencode", [], { + const opencodeArgs = sessionId ? ["-s", sessionId] : [] + const opencodeProcess = spawn("opencode", opencodeArgs, { stdio: "inherit", cwd: process.cwd(), }) From 0b86adbe997320c1a13e91899cace1ddd956a39a Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:32:44 -0800 Subject: [PATCH 04/20] feat: agent color cfg (#4226) Co-authored-by: 0xrin <0xrin1@protonmail.com> Co-authored-by: GitHub Action --- packages/opencode/src/agent/agent.ts | 4 +- .../src/cli/cmd/tui/context/local.tsx | 2 + packages/opencode/src/config/config.ts | 5 ++ packages/opencode/src/util/color.ts | 19 ++++++ .../opencode/test/config/agent-color.test.ts | 66 +++++++++++++++++++ packages/sdk/go/agent.go | 2 + packages/sdk/js/src/gen/types.gen.ts | 5 ++ 7 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 packages/opencode/src/util/color.ts create mode 100644 packages/opencode/test/config/agent-color.test.ts diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index f1050ae72a..867bc0fe9e 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -16,6 +16,7 @@ export namespace Agent { builtIn: z.boolean(), topP: z.number().optional(), temperature: z.number().optional(), + color: z.string().optional(), permission: z.object({ edit: Config.Permission, bash: z.record(z.string(), Config.Permission), @@ -147,7 +148,7 @@ export namespace Agent { tools: {}, builtIn: false, } - const { name, model, prompt, tools, description, temperature, top_p, mode, permission, ...extra } = value + const { name, model, prompt, tools, description, temperature, top_p, mode, permission, color, ...extra } = value item.options = { ...item.options, ...extra, @@ -167,6 +168,7 @@ export namespace Agent { if (temperature != undefined) item.temperature = temperature if (top_p != undefined) item.topP = top_p if (mode) item.mode = mode + if (color) item.color = color // just here for consistency & to prevent it from being added as an option if (name) item.name = name diff --git a/packages/opencode/src/cli/cmd/tui/context/local.tsx b/packages/opencode/src/cli/cmd/tui/context/local.tsx index fe81fd180a..998739f120 100644 --- a/packages/opencode/src/cli/cmd/tui/context/local.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/local.tsx @@ -90,6 +90,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ }) }, color(name: string) { + const agent = agents().find((x) => x.name === name) + if (agent?.color) return agent.color const index = agents().findIndex((x) => x.name === name) return colors()[index % colors().length] }, diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index eaac1dd4f3..8823c866e2 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -355,6 +355,11 @@ export namespace Config { disable: z.boolean().optional(), description: z.string().optional().describe("Description of when to use the agent"), mode: z.union([z.literal("subagent"), z.literal("primary"), z.literal("all")]).optional(), + color: z + .string() + .regex(/^#[0-9a-fA-F]{6}$/, "Invalid hex color format") + .optional() + .describe("Hex color code for the agent (e.g., #FF5733)"), permission: z .object({ edit: Permission.optional(), diff --git a/packages/opencode/src/util/color.ts b/packages/opencode/src/util/color.ts new file mode 100644 index 0000000000..b96deaec47 --- /dev/null +++ b/packages/opencode/src/util/color.ts @@ -0,0 +1,19 @@ +export namespace Color { + export function isValidHex(hex?: string): hex is string { + if (!hex) return false + return /^#[0-9a-fA-F]{6}$/.test(hex) + } + + export function hexToRgb(hex: string): { r: number; g: number; b: number } { + const r = parseInt(hex.slice(1, 3), 16) + const g = parseInt(hex.slice(3, 5), 16) + const b = parseInt(hex.slice(5, 7), 16) + return { r, g, b } + } + + export function hexToAnsiBold(hex?: string): string | undefined { + if (!isValidHex(hex)) return undefined + const { r, g, b } = hexToRgb(hex) + return `\x1b[38;2;${r};${g};${b}m\x1b[1m` + } +} diff --git a/packages/opencode/test/config/agent-color.test.ts b/packages/opencode/test/config/agent-color.test.ts new file mode 100644 index 0000000000..a2c3742967 --- /dev/null +++ b/packages/opencode/test/config/agent-color.test.ts @@ -0,0 +1,66 @@ +import { test, expect } from "bun:test" +import path from "path" +import { tmpdir } from "../fixture/fixture" +import { Instance } from "../../src/project/instance" +import { Config } from "../../src/config/config" +import { Agent as AgentSvc } from "../../src/agent/agent" +import { Color } from "../../src/util/color" + +test("agent color parsed from project config", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + agent: { + build: { color: "#FFA500" }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const cfg = await Config.get() + expect(cfg.agent?.["build"]?.color).toBe("#FFA500") + }, + }) +}) + +test("Agent.get includes color from config", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + agent: { + plan: { color: "#A855F7" }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const plan = await AgentSvc.get("plan") + expect(plan?.color).toBe("#A855F7") + }, + }) +}) + +test("Color.hexToAnsiBold converts valid hex to ANSI", () => { + const result = Color.hexToAnsiBold("#FFA500") + expect(result).toBe("\x1b[38;2;255;165;0m\x1b[1m") +}) + +test("Color.hexToAnsiBold returns undefined for invalid hex", () => { + expect(Color.hexToAnsiBold(undefined)).toBeUndefined() + expect(Color.hexToAnsiBold("")).toBeUndefined() + expect(Color.hexToAnsiBold("#FFF")).toBeUndefined() + expect(Color.hexToAnsiBold("FFA500")).toBeUndefined() + expect(Color.hexToAnsiBold("#GGGGGG")).toBeUndefined() +}) diff --git a/packages/sdk/go/agent.go b/packages/sdk/go/agent.go index 3413b56664..d1bb36e36d 100644 --- a/packages/sdk/go/agent.go +++ b/packages/sdk/go/agent.go @@ -49,6 +49,7 @@ type Agent struct { Options map[string]interface{} `json:"options,required"` Permission AgentPermission `json:"permission,required"` Tools map[string]bool `json:"tools,required"` + Color string `json:"color"` Description string `json:"description"` Model AgentModel `json:"model"` Prompt string `json:"prompt"` @@ -65,6 +66,7 @@ type agentJSON struct { Options apijson.Field Permission apijson.Field Tools apijson.Field + Color apijson.Field Description apijson.Field Model apijson.Field Prompt apijson.Field diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 19f7a3a77d..3e64fc9a01 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -190,6 +190,10 @@ export type AgentConfig = { */ description?: string mode?: "subagent" | "primary" | "all" + /** + * Hex color code for the agent (e.g., #FF5733) + */ + color?: string permission?: { edit?: "ask" | "allow" | "deny" bash?: @@ -1043,6 +1047,7 @@ export type Agent = { builtIn: boolean topP?: number temperature?: number + color?: string permission: { edit: "ask" | "allow" | "deny" bash: { From 9990e84d372cd4572c91f3f529e7b1f21b8f0c40 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:08:59 -0800 Subject: [PATCH 05/20] fix: ensure revert dialog moves that prompt to input box (#4227) --- .../cmd/tui/routes/session/dialog-message.tsx | 28 +++++++++++++++++-- .../src/cli/cmd/tui/routes/session/index.tsx | 8 +++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx index ee2b77afc9..a59fad7b18 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx @@ -3,8 +3,13 @@ import { useSync } from "@tui/context/sync" import { DialogSelect } from "@tui/ui/dialog-select" import { useSDK } from "@tui/context/sdk" import { useRoute } from "@tui/context/route" +import type { PromptInfo } from "@tui/component/prompt/history" -export function DialogMessage(props: { messageID: string; sessionID: string }) { +export function DialogMessage(props: { + messageID: string + sessionID: string + setPrompt?: (prompt: PromptInfo) => void +}) { const sync = useSync() const sdk = useSDK() const message = createMemo(() => sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID)) @@ -19,14 +24,33 @@ export function DialogMessage(props: { messageID: string; sessionID: string }) { value: "session.revert", description: "undo messages and file changes", onSelect: (dialog) => { + const msg = message() + if (!msg) return + sdk.client.session.revert({ path: { id: props.sessionID, }, body: { - messageID: message()!.id, + messageID: msg.id, }, }) + + if (props.setPrompt) { + const parts = sync.data.part[msg.id] + const promptInfo = parts.reduce( + (agg, part) => { + if (part.type === "text") { + if (!part.synthetic) agg.input += part.text + } + if (part.type === "file") agg.parts.push(part) + return agg + }, + { input: "", parts: [] as PromptInfo["parts"] }, + ) + props.setPrompt(promptInfo) + } + dialog.clear() }, }, 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 7b25da3972..4c3dd96ff5 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -757,7 +757,13 @@ export function Session() { index={index()} onMouseUp={() => { if (renderer.getSelection()?.getSelectedText()) return - dialog.replace(() => ) + dialog.replace(() => ( + prompt.set(promptInfo)} + /> + )) }} message={message as UserMessage} parts={sync.data.part[message.id] ?? []} From c07d6487a85420b13832caef258bdd1d6550af33 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:27:34 -0800 Subject: [PATCH 06/20] fix config ordering (#4228) --- packages/opencode/src/config/config.ts | 28 +++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 8823c866e2..e6bed238ff 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -24,12 +24,6 @@ export namespace Config { export const state = Instance.state(async () => { const auth = await Auth.all() let result = await global() - for (const file of ["opencode.jsonc", "opencode.json"]) { - const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree) - for (const resolved of found.toReversed()) { - result = mergeDeep(result, await loadFile(resolved)) - } - } // Override with custom config if provided if (Flag.OPENCODE_CONFIG) { @@ -37,6 +31,13 @@ export namespace Config { log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG }) } + for (const file of ["opencode.jsonc", "opencode.json"]) { + const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree) + for (const resolved of found.toReversed()) { + result = mergeDeep(result, await loadFile(resolved)) + } + } + if (Flag.OPENCODE_CONFIG_CONTENT) { result = mergeDeep(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT)) log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT") @@ -74,12 +75,15 @@ export namespace Config { for (const dir of directories) { await assertValid(dir) - for (const file of ["opencode.jsonc", "opencode.json"]) { - result = mergeDeep(result, await loadFile(path.join(dir, file))) - // to satisy the type checker - result.agent ??= {} - result.mode ??= {} - result.plugin ??= [] + if (dir.endsWith(".opencode")) { + for (const file of ["opencode.jsonc", "opencode.json"]) { + log.debug(`loading config from ${path.join(dir, file)}`) + result = mergeDeep(result, await loadFile(path.join(dir, file))) + // to satisy the type checker + result.agent ??= {} + result.mode ??= {} + result.plugin ??= [] + } } promises.push(installDependencies(dir)) From 491a2adf8d61cb52aa5d8a6c3b3e5fe0ef073a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Krzywa=C5=BCnia?= <1815898+ribelo@users.noreply.github.com> Date: Wed, 12 Nov 2025 02:38:50 +0100 Subject: [PATCH 07/20] fix: resolve @file references in slash commands with subagents (#4221) --- packages/opencode/src/session/prompt.ts | 94 +++++++++++++------------ packages/opencode/src/tool/task.ts | 9 +-- 2 files changed, 51 insertions(+), 52 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 10a9727a0f..f4dc84be58 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -145,6 +145,54 @@ export namespace SessionPrompt { ), }) export type PromptInput = z.infer + + export async function resolvePromptParts(template: string): Promise { + const parts: PromptInput["parts"] = [ + { + type: "text", + text: template, + }, + ] + const files = ConfigMarkdown.files(template) + await Promise.all( + files.map(async (match) => { + const name = match[1] + const filepath = name.startsWith("~/") + ? path.join(os.homedir(), name.slice(2)) + : path.resolve(Instance.worktree, name) + + const stats = await fs.stat(filepath).catch(() => undefined) + if (!stats) { + const agent = await Agent.get(name) + if (agent) { + parts.push({ + type: "agent", + name: agent.name, + }) + } + return + } + + if (stats.isDirectory()) { + parts.push({ + type: "file", + url: `file://${filepath}`, + filename: name, + mime: "application/x-directory", + }) + return + } + + parts.push({ + type: "file", + url: `file://${filepath}`, + filename: name, + mime: "text/plain", + }) + }), + ) + return parts + } export async function prompt(input: PromptInput): Promise { const l = log.clone().tag("session", input.sessionID) l.info("prompt") @@ -1605,51 +1653,7 @@ export namespace SessionPrompt { } template = template.trim() - const parts = [ - { - type: "text", - text: template, - }, - ] as PromptInput["parts"] - - const files = ConfigMarkdown.files(template) - await Promise.all( - files.map(async (match) => { - const name = match[1] - const filepath = name.startsWith("~/") - ? path.join(os.homedir(), name.slice(2)) - : path.resolve(Instance.worktree, name) - - const stats = await fs.stat(filepath).catch(() => undefined) - if (!stats) { - const agent = await Agent.get(name) - if (agent) { - parts.push({ - type: "agent", - name: agent.name, - }) - } - return - } - - if (stats.isDirectory()) { - parts.push({ - type: "file", - url: `file://${filepath}`, - filename: name, - mime: "application/x-directory", - }) - return - } - - parts.push({ - type: "file", - url: `file://${filepath}`, - filename: name, - mime: "text/plain", - }) - }), - ) + const parts = await resolvePromptParts(template) const model = await (async () => { if (command.model) { diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 845a0e8c8b..a5369d3354 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -65,6 +65,7 @@ export const TaskTool = Tool.define("task", async () => { ctx.abort.addEventListener("abort", () => { SessionLock.abort(session.id) }) + const promptParts = await SessionPrompt.resolvePromptParts(params.prompt) const result = await SessionPrompt.prompt({ messageID, sessionID: session.id, @@ -79,13 +80,7 @@ export const TaskTool = Tool.define("task", async () => { task: false, ...agent.tools, }, - parts: [ - { - id: Identifier.ascending("part"), - type: "text", - text: params.prompt, - }, - ], + parts: promptParts, }) unsub() let all From 7e29e1dd23c3d809f0da4dffbbdbb7350c8819cf Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 11 Nov 2025 21:01:31 -0500 Subject: [PATCH 08/20] better errors on initial tui boot --- packages/opencode/src/cli/cmd/tui/context/sync.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index e53cd60b9f..6899cf575b 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -217,9 +217,9 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ // blocking Promise.all([ - sdk.client.config.providers().then((x) => setStore("provider", x.data!.providers)), - sdk.client.app.agents().then((x) => setStore("agent", x.data ?? [])), - sdk.client.config.get().then((x) => setStore("config", x.data!)), + sdk.client.config.providers({ throwOnError: true }).then((x) => setStore("provider", x.data!.providers)), + sdk.client.app.agents({ throwOnError: true }).then((x) => setStore("agent", x.data ?? [])), + sdk.client.config.get({ throwOnError: true }).then((x) => setStore("config", x.data!)), ]).then(() => { setStore("status", "partial") // non-blocking From 0bd11e970b723b8cd59c14dd55e00829d9dcb862 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 12 Nov 2025 02:07:41 +0000 Subject: [PATCH 09/20] release: v1.0.59 --- bun.lock | 22 +++++++++++----------- 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/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/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/bun.lock b/bun.lock index a3a801f5f6..f3c4eedda6 100644 --- a/bun.lock +++ b/bun.lock @@ -40,7 +40,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -67,7 +67,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -91,7 +91,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -115,7 +115,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -155,7 +155,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -171,7 +171,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.58", + "version": "1.0.59", "bin": { "opencode": "./bin/opencode", }, @@ -249,7 +249,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -269,7 +269,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.58", + "version": "1.0.59", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -280,7 +280,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -293,7 +293,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.58", + "version": "1.0.59", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -323,7 +323,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.58", + "version": "1.0.59", "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 4dcd9614b5..a9c4e5a71e 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.58" + "version": "1.0.59" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index ad08dd3697..67d168786c 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.58", + "version": "1.0.59", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 0f83a6e221..56104b4507 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.58", + "version": "1.0.59", "$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 1fb91fb641..ed703c33d5 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.58", + "version": "1.0.59", "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 f92db4a5d5..db9b29b51f 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.58", + "version": "1.0.59", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index c6889fe191..22d991b183 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.58" +version = "1.0.59" 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.58/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.59/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.58/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.58/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.58/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.58/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 7647c021fb..441e129566 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.58", + "version": "1.0.59", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index bb79920964..20bbf040c8 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.58", + "version": "1.0.59", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index b272c25fab..675971e2b0 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.58", + "version": "1.0.59", "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 956d7d13a4..4e1b0df727 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.58", + "version": "1.0.59", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 0e377a088d..b178b169d9 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.58", + "version": "1.0.59", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 7473c7a23c..a6275d0fd7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.58", + "version": "1.0.59", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index f762d66955..a50eb97376 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.58", + "version": "1.0.59", "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 34d131e689..b83ffe0545 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.58", + "version": "1.0.59", "publisher": "sst-dev", "repository": { "type": "git", From d81dce6a82d670d69e813a1bba67b9f06698d30b Mon Sep 17 00:00:00 2001 From: Dax Date: Tue, 11 Nov 2025 21:30:38 -0500 Subject: [PATCH 10/20] fix: add support for loading custom themes from .opencode/themes directory (#4229) Co-authored-by: GitHub Action --- .opencode/themes/mytheme.json | 223 ++++++++++++++++++ .../src/cli/cmd/tui/context/theme.tsx | 47 +++- packages/opencode/src/server/server.ts | 1 + packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 5 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 .opencode/themes/mytheme.json diff --git a/.opencode/themes/mytheme.json b/.opencode/themes/mytheme.json new file mode 100644 index 0000000000..e444de807c --- /dev/null +++ b/.opencode/themes/mytheme.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://opencode.ai/theme.json", + "defs": { + "nord0": "#2E3440", + "nord1": "#3B4252", + "nord2": "#434C5E", + "nord3": "#4C566A", + "nord4": "#D8DEE9", + "nord5": "#E5E9F0", + "nord6": "#ECEFF4", + "nord7": "#8FBCBB", + "nord8": "#88C0D0", + "nord9": "#81A1C1", + "nord10": "#5E81AC", + "nord11": "#BF616A", + "nord12": "#D08770", + "nord13": "#EBCB8B", + "nord14": "#A3BE8C", + "nord15": "#B48EAD" + }, + "theme": { + "primary": { + "dark": "nord8", + "light": "nord10" + }, + "secondary": { + "dark": "nord9", + "light": "nord9" + }, + "accent": { + "dark": "nord7", + "light": "nord7" + }, + "error": { + "dark": "nord11", + "light": "nord11" + }, + "warning": { + "dark": "nord12", + "light": "nord12" + }, + "success": { + "dark": "nord14", + "light": "nord14" + }, + "info": { + "dark": "nord8", + "light": "nord10" + }, + "text": { + "dark": "nord4", + "light": "nord0" + }, + "textMuted": { + "dark": "nord3", + "light": "nord1" + }, + "background": { + "dark": "nord0", + "light": "nord6" + }, + "backgroundPanel": { + "dark": "nord1", + "light": "nord5" + }, + "backgroundElement": { + "dark": "nord1", + "light": "nord4" + }, + "border": { + "dark": "nord2", + "light": "nord3" + }, + "borderActive": { + "dark": "nord3", + "light": "nord2" + }, + "borderSubtle": { + "dark": "nord2", + "light": "nord3" + }, + "diffAdded": { + "dark": "nord14", + "light": "nord14" + }, + "diffRemoved": { + "dark": "nord11", + "light": "nord11" + }, + "diffContext": { + "dark": "nord3", + "light": "nord3" + }, + "diffHunkHeader": { + "dark": "nord3", + "light": "nord3" + }, + "diffHighlightAdded": { + "dark": "nord14", + "light": "nord14" + }, + "diffHighlightRemoved": { + "dark": "nord11", + "light": "nord11" + }, + "diffAddedBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffRemovedBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffContextBg": { + "dark": "nord1", + "light": "nord5" + }, + "diffLineNumber": { + "dark": "nord2", + "light": "nord4" + }, + "diffAddedLineNumberBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "diffRemovedLineNumberBg": { + "dark": "#3B4252", + "light": "#E5E9F0" + }, + "markdownText": { + "dark": "nord4", + "light": "nord0" + }, + "markdownHeading": { + "dark": "nord8", + "light": "nord10" + }, + "markdownLink": { + "dark": "nord9", + "light": "nord9" + }, + "markdownLinkText": { + "dark": "nord7", + "light": "nord7" + }, + "markdownCode": { + "dark": "nord14", + "light": "nord14" + }, + "markdownBlockQuote": { + "dark": "nord3", + "light": "nord3" + }, + "markdownEmph": { + "dark": "nord12", + "light": "nord12" + }, + "markdownStrong": { + "dark": "nord13", + "light": "nord13" + }, + "markdownHorizontalRule": { + "dark": "nord3", + "light": "nord3" + }, + "markdownListItem": { + "dark": "nord8", + "light": "nord10" + }, + "markdownListEnumeration": { + "dark": "nord7", + "light": "nord7" + }, + "markdownImage": { + "dark": "nord9", + "light": "nord9" + }, + "markdownImageText": { + "dark": "nord7", + "light": "nord7" + }, + "markdownCodeBlock": { + "dark": "nord4", + "light": "nord0" + }, + "syntaxComment": { + "dark": "nord3", + "light": "nord3" + }, + "syntaxKeyword": { + "dark": "nord9", + "light": "nord9" + }, + "syntaxFunction": { + "dark": "nord8", + "light": "nord8" + }, + "syntaxVariable": { + "dark": "nord7", + "light": "nord7" + }, + "syntaxString": { + "dark": "nord14", + "light": "nord14" + }, + "syntaxNumber": { + "dark": "nord15", + "light": "nord15" + }, + "syntaxType": { + "dark": "nord7", + "light": "nord7" + }, + "syntaxOperator": { + "dark": "nord9", + "light": "nord9" + }, + "syntaxPunctuation": { + "dark": "nord4", + "light": "nord0" + } + } +} diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 74c2ff7f0d..2a79620e6e 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -1,5 +1,6 @@ import { SyntaxStyle, RGBA, type TerminalColors } from "@opentui/core" -import { createMemo } from "solid-js" +import path from "path" +import { createEffect, createMemo, onMount } from "solid-js" import { useSync } from "@tui/context/sync" import { createSimpleContext } from "./helper" import aura from "./theme/aura.json" with { type: "json" } @@ -27,7 +28,9 @@ import vesper from "./theme/vesper.json" with { type: "json" } import zenburn from "./theme/zenburn.json" with { type: "json" } import { useKV } from "./kv" import { useRenderer } from "@opentui/solid" -import { createStore } from "solid-js/store" +import { createStore, produce } from "solid-js/store" +import { Global } from "@/global" +import { Filesystem } from "@/util/filesystem" type Theme = { primary: RGBA @@ -144,6 +147,17 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ themes: DEFAULT_THEMES, mode: props.mode, active: (sync.data.config.theme ?? kv.get("theme", "opencode")) as string, + ready: false, + }) + + createEffect(async () => { + const custom = await getCustomThemes() + setStore( + produce((draft) => { + Object.assign(draft.themes, custom) + draft.ready = true + }), + ) }) const renderer = useRenderer() @@ -187,12 +201,39 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ kv.set("theme", theme) }, get ready() { - return sync.ready + return store.ready }, } }, }) +const CUSTOM_THEME_GLOB = new Bun.Glob("themes/*.json") +async function getCustomThemes() { + const directories = [ + Global.Path.config, + ...(await Array.fromAsync( + Filesystem.up({ + targets: [".opencode"], + start: process.cwd(), + }), + )), + ] + + const result: Record = {} + for (const dir of directories) { + for await (const item of CUSTOM_THEME_GLOB.scan({ + absolute: true, + followSymlinks: true, + dot: true, + cwd: dir, + })) { + const name = path.basename(item, ".json") + result[name] = await Bun.file(item).json() + } + } + return result +} + function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJson { const bg = RGBA.fromHex(colors.defaultBackground ?? colors.palette[0]!) const fg = RGBA.fromHex(colors.defaultForeground ?? colors.palette[7]!) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 106693b22f..2dee6c915f 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -163,6 +163,7 @@ export namespace Server { return c.json(await Config.get()) }, ) + .patch( "/config", describeRoute({ diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 675971e2b0..427ea3e408 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 4e1b0df727..c4530dc650 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 6f37315cd1150aea1ac688d82adc8add469f7478 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 12 Nov 2025 02:36:42 +0000 Subject: [PATCH 11/20] release: v1.0.60 --- bun.lock | 22 +++++++++++----------- 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/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/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/bun.lock b/bun.lock index f3c4eedda6..0f201c79f1 100644 --- a/bun.lock +++ b/bun.lock @@ -40,7 +40,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -67,7 +67,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -91,7 +91,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -115,7 +115,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -155,7 +155,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -171,7 +171,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.59", + "version": "1.0.60", "bin": { "opencode": "./bin/opencode", }, @@ -249,7 +249,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -269,7 +269,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.59", + "version": "1.0.60", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -280,7 +280,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -293,7 +293,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.59", + "version": "1.0.60", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -323,7 +323,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.59", + "version": "1.0.60", "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 a9c4e5a71e..63d552e313 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.59" + "version": "1.0.60" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 67d168786c..966697b88f 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.59", + "version": "1.0.60", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 56104b4507..da8574c30b 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.59", + "version": "1.0.60", "$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 ed703c33d5..1035658b99 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.59", + "version": "1.0.60", "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 db9b29b51f..ec994fb509 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.59", + "version": "1.0.60", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 22d991b183..1b7229022c 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.59" +version = "1.0.60" 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.59/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.60/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.59/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.59/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 441e129566..8016a508e7 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.59", + "version": "1.0.60", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 20bbf040c8..c8c2479027 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.59", + "version": "1.0.60", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 427ea3e408..4aac8c25b9 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.59", + "version": "1.0.60", "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 c4530dc650..f556154f23 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.59", + "version": "1.0.60", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index b178b169d9..7f9b15245d 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.59", + "version": "1.0.60", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index a6275d0fd7..e0ac164cdc 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.59", + "version": "1.0.60", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index a50eb97376..be14a7c379 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.59", + "version": "1.0.60", "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 b83ffe0545..5e72f5375f 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.59", + "version": "1.0.60", "publisher": "sst-dev", "repository": { "type": "git", From ad83dd3ad99cb6ec37c482d7f09485fd3689c420 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 11 Nov 2025 21:35:13 -0500 Subject: [PATCH 12/20] tui: fix autocomplete display to prevent long file paths from breaking layout --- .../src/cli/cmd/tui/component/prompt/autocomplete.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 a776b5f951..cb7be2f452 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -8,6 +8,7 @@ import { useSync } from "@tui/context/sync" import { useTheme } from "@tui/context/theme" import { SplitBorder } from "@tui/component/border" import { useCommandDialog } from "@tui/component/dialog-command" +import { Locale } from "@/util/locale" import type { PromptInfo } from "./history" export type AutocompleteRef = { @@ -125,10 +126,11 @@ export function Autocomplete(props: { // Add file options if (!result.error && result.data) { + const width = store.position.width - 4 options.push( ...result.data.map( (item): AutocompleteOption => ({ - display: item, + display: Locale.truncateMiddle(item, width), onSelect: () => { insertPart(item, { type: "file", From 18260b037bf8d99da52f7179c488bf183850c26e Mon Sep 17 00:00:00 2001 From: Boston Cartwright Date: Tue, 11 Nov 2025 19:51:33 -0700 Subject: [PATCH 13/20] feat: add SourceKit LSP support (#1545) Co-authored-by: GitHub Action Co-authored-by: Aiden Cline --- packages/opencode/src/lsp/server.ts | 34 ++++++++++++++++++++++++ packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/web/src/content/docs/lsp.mdx | 37 ++++++++++++++------------- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 1132bbc7c3..d9fff5b113 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -547,6 +547,40 @@ export namespace LSPServer { }, } + export const SourceKit: Info = { + id: "sourcekit-lsp", + extensions: [".swift", ".objc", "objcpp"], + root: NearestRoot(["Package.swift", "*.xcodeproj", "*.xcworkspace"]), + async spawn(root) { + // Check if sourcekit-lsp is available in the PATH + // This is installed with the Swift toolchain + const sourcekit = Bun.which("sourcekit-lsp") + if (sourcekit) { + return { + process: spawn(sourcekit, { + cwd: root, + }), + } + } + + // If sourcekit-lsp not found, check if xcrun is available + // This is specific to macOS where sourcekit-lsp is typically installed with Xcode + if (!Bun.which("xcrun")) return + + const lspLoc = await $`xcrun --find sourcekit-lsp`.quiet().nothrow() + + if (lspLoc.exitCode !== 0) return + + const bin = lspLoc.text().trim() + + return { + process: spawn(bin, { + cwd: root, + }), + } + }, + } + export const RustAnalyzer: Info = { id: "rust", root: async (root) => { diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 4aac8c25b9..c9b2a0e978 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 f556154f23..d6da3b7631 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx index 97aadab575..1cd1d82586 100644 --- a/packages/web/src/content/docs/lsp.mdx +++ b/packages/web/src/content/docs/lsp.mdx @@ -11,24 +11,25 @@ OpenCode integrates with your Language Server Protocol (LSP) to help the LLM int OpenCode comes with several built-in LSP servers for popular languages: -| LSP Server | Extensions | Requirements | -| ---------- | ---------------------------------------------------- | ------------------------------------------------------------ | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | -| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | -| gopls | .go | `go` command available | -| ruby-lsp | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | -| pyright | .py, .pyi | `pyright` dependency installed | -| elixir-ls | .ex, .exs | `elixir` command available | -| zls | .zig, .zon | `zig` command available | -| csharp | .cs | `.NET SDK` installed | -| vue | .vue | Auto-installs for Vue projects | -| rust | .rs | `rust-analyzer` command available | -| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | -| svelte | .svelte | Auto-installs for Svelte projects | -| astro | .astro | Auto-installs for Astro projects | -| jdtls | .java | `Java SDK (version 21+)` installed | -| lua-ls | .lua | Auto-installs for Lua projects | +| LSP Server | Extensions | Requirements | +| ------------- | ---------------------------------------------------- | ------------------------------------------------------------ | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | +| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | +| gopls | .go | `go` command available | +| ruby-lsp | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | +| pyright | .py, .pyi | `pyright` dependency installed | +| elixir-ls | .ex, .exs | `elixir` command available | +| zls | .zig, .zon | `zig` command available | +| csharp | .cs | `.NET SDK` installed | +| vue | .vue | Auto-installs for Vue projects | +| rust | .rs | `rust-analyzer` command available | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | +| svelte | .svelte | Auto-installs for Svelte projects | +| astro | .astro | Auto-installs for Astro projects | +| jdtls | .java | `Java SDK (version 21+)` installed | +| lua-ls | .lua | Auto-installs for Lua projects | +| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) | LSP servers are automatically enabled when one of the above file extensions are detected and the requirements are met. From e3a2728fa3cf331b6d075dbfd6543990083c72eb Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 11 Nov 2025 22:03:54 -0500 Subject: [PATCH 14/20] tui: add double-esc interrupt mechanism for long-running operations Users can now press escape twice within 5 seconds to interrupt long-running operations in the TUI. The first press shows a visual hint, and the second press aborts the current session. --- .../cli/cmd/tui/component/prompt/index.tsx | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 408c62cde8..a7f248758b 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -228,11 +228,21 @@ export function Prompt(props: PromptProps) { if (!props.sessionID) return if (autocomplete.visible) return if (!input.focused) return - sdk.client.session.abort({ - path: { - id: props.sessionID, - }, - }) + + setStore("interrupt", store.interrupt + 1) + + setTimeout(() => { + setStore("interrupt", 0) + }, 5000) + + if (store.interrupt >= 2) { + sdk.client.session.abort({ + path: { + id: props.sessionID, + }, + }) + setStore("interrupt", 0) + } dialog.clear() }, }, @@ -252,6 +262,7 @@ export function Prompt(props: PromptProps) { prompt: PromptInfo mode: "normal" | "shell" extmarkToPartIndex: Map + interrupt: number }>({ prompt: { input: "", @@ -259,6 +270,7 @@ export function Prompt(props: PromptProps) { }, mode: "normal", extmarkToPartIndex: new Map(), + interrupt: 0, }) createEffect(() => { @@ -746,8 +758,11 @@ export function Prompt(props: PromptProps) { - - esc interrupt + 0 ? theme.primary : theme.text}> + esc{" "} + 0 ? theme.primary : theme.textMuted }}> + {store.interrupt > 0 ? "again to interrupt" : "interrupt"} + From 7c2d4ee79aed9d368f9684e4e9e88ffaf8de2d58 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 12 Nov 2025 03:10:55 +0000 Subject: [PATCH 15/20] release: v1.0.61 --- bun.lock | 22 +++++++++++----------- 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/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/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/bun.lock b/bun.lock index 0f201c79f1..b889d4e9d1 100644 --- a/bun.lock +++ b/bun.lock @@ -40,7 +40,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -67,7 +67,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -91,7 +91,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -115,7 +115,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -155,7 +155,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -171,7 +171,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.60", + "version": "1.0.61", "bin": { "opencode": "./bin/opencode", }, @@ -249,7 +249,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -269,7 +269,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.60", + "version": "1.0.61", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -280,7 +280,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -293,7 +293,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.60", + "version": "1.0.61", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -323,7 +323,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.60", + "version": "1.0.61", "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 63d552e313..8768752720 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.60" + "version": "1.0.61" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 966697b88f..781f9f5ab1 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.60", + "version": "1.0.61", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index da8574c30b..097dbd6d36 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.60", + "version": "1.0.61", "$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 1035658b99..9e3aefe5a6 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.60", + "version": "1.0.61", "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 ec994fb509..143b023fe3 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.60", + "version": "1.0.61", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 1b7229022c..b0c66eb41b 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.60" +version = "1.0.61" 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.60/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.61/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.60/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.61/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.61/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.61/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.60/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.61/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 8016a508e7..5a680fa7ba 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.60", + "version": "1.0.61", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index c8c2479027..055ae8fb76 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.60", + "version": "1.0.61", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index c9b2a0e978..56269395bb 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.60", + "version": "1.0.61", "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 d6da3b7631..8739e74e0c 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.60", + "version": "1.0.61", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 7f9b15245d..f14ddc4858 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.60", + "version": "1.0.61", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index e0ac164cdc..348d75b7d9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.60", + "version": "1.0.61", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index be14a7c379..caea252e61 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.60", + "version": "1.0.61", "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 5e72f5375f..cbb3080bdd 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.60", + "version": "1.0.61", "publisher": "sst-dev", "repository": { "type": "git", From aa2e2c76c0f44c3676d1b3d3ce03716e82408391 Mon Sep 17 00:00:00 2001 From: Filip <34747899+neriousy@users.noreply.github.com> Date: Wed, 12 Nov 2025 07:21:55 +0100 Subject: [PATCH 16/20] fix: clangd hanging fixed (#3611) Co-authored-by: Aiden Cline Co-authored-by: GitHub Action --- packages/opencode/src/lsp/index.ts | 91 ++++++++++---- packages/opencode/src/lsp/server.ts | 188 ++++++++++++++++++---------- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 4 files changed, 191 insertions(+), 92 deletions(-) diff --git a/packages/opencode/src/lsp/index.ts b/packages/opencode/src/lsp/index.ts index 44cf263f0e..6b53797422 100644 --- a/packages/opencode/src/lsp/index.ts +++ b/packages/opencode/src/lsp/index.ts @@ -103,6 +103,7 @@ export namespace LSP { broken: new Set(), servers, clients, + spawning: new Map>(), } }, async (state) => { @@ -145,6 +146,49 @@ export namespace LSP { const s = await state() const extension = path.parse(file).ext || file const result: LSPClient.Info[] = [] + + async function schedule(server: LSPServer.Info, root: string, key: string) { + const handle = await server + .spawn(root) + .then((value) => { + if (!value) s.broken.add(key) + return value + }) + .catch((err) => { + s.broken.add(key) + log.error(`Failed to spawn LSP server ${server.id}`, { error: err }) + return undefined + }) + + if (!handle) return undefined + log.info("spawned lsp server", { serverID: server.id }) + + const client = await LSPClient.create({ + serverID: server.id, + server: handle, + root, + }).catch((err) => { + s.broken.add(key) + handle.process.kill() + log.error(`Failed to initialize LSP client ${server.id}`, { error: err }) + return undefined + }) + + if (!client) { + handle.process.kill() + return undefined + } + + const existing = s.clients.find((x) => x.root === root && x.serverID === server.id) + if (existing) { + handle.process.kill() + return existing + } + + s.clients.push(client) + return client + } + for (const server of Object.values(s.servers)) { if (server.extensions.length && !server.extensions.includes(extension)) continue const root = await server.root(file) @@ -156,39 +200,31 @@ export namespace LSP { result.push(match) continue } - const handle = await server - .spawn(root) - .then((h) => { - if (h === undefined) { - s.broken.add(root + server.id) - } - return h - }) - .catch((err) => { - s.broken.add(root + server.id) - log.error(`Failed to spawn LSP server ${server.id}`, { error: err }) - return undefined - }) - if (!handle) continue - log.info("spawned lsp server", { serverID: server.id }) - const client = await LSPClient.create({ - serverID: server.id, - server: handle, - root, - }).catch((err) => { - s.broken.add(root + server.id) - handle.process.kill() - log.error(`Failed to initialize LSP client ${server.id}`, { - error: err, - }) - return undefined + const inflight = s.spawning.get(root + server.id) + if (inflight) { + const client = await inflight + if (!client) continue + result.push(client) + continue + } + + const task = schedule(server, root, root + server.id) + s.spawning.set(root + server.id, task) + + task.finally(() => { + if (s.spawning.get(root + server.id) === task) { + s.spawning.delete(root + server.id) + } }) + + const client = await task if (!client) continue - s.clients.push(client) + result.push(client) Bus.publish(Event.Updated, {}) } + return result } @@ -199,6 +235,7 @@ export namespace LSP { if (!clients.includes(client)) return const wait = waitForDiagnostics ? client.waitForDiagnostics({ path: input }) : Promise.resolve() await client.notify.open({ path: input }) + return wait }).catch((err) => { log.error("failed to touch file", { err, file: input }) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index d9fff5b113..281d1a0ed4 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -632,73 +632,135 @@ export namespace LSPServer { root: NearestRoot(["compile_commands.json", "compile_flags.txt", ".clangd", "CMakeLists.txt", "Makefile"]), extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"], async spawn(root) { - let bin = Bun.which("clangd", { - PATH: process.env["PATH"] + ":" + Global.Path.bin, - }) - if (!bin) { - if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return - log.info("downloading clangd from GitHub releases") - - const releaseResponse = await fetch("https://api.github.com/repos/clangd/clangd/releases/latest") - if (!releaseResponse.ok) { - log.error("Failed to fetch clangd release info") - return + const args = ["--background-index", "--clang-tidy"] + const fromPath = Bun.which("clangd") + if (fromPath) { + return { + process: spawn(fromPath, args, { + cwd: root, + }), } - - const release = (await releaseResponse.json()) as any - - const platform = process.platform - let assetName = "" - - if (platform === "darwin") { - assetName = "clangd-mac-" - } else if (platform === "linux") { - assetName = "clangd-linux-" - } else if (platform === "win32") { - assetName = "clangd-windows-" - } else { - log.error(`Platform ${platform} is not supported by clangd auto-download`) - return - } - - assetName += release.tag_name + ".zip" - - const asset = release.assets.find((a: any) => a.name === assetName) - if (!asset) { - log.error(`Could not find asset ${assetName} in latest clangd release`) - return - } - - const downloadUrl = asset.browser_download_url - const downloadResponse = await fetch(downloadUrl) - if (!downloadResponse.ok) { - log.error("Failed to download clangd") - return - } - - const zipPath = path.join(Global.Path.bin, "clangd.zip") - await Bun.file(zipPath).write(downloadResponse) - - await $`unzip -o -q ${zipPath}`.quiet().cwd(Global.Path.bin).nothrow() - await fs.rm(zipPath, { force: true }) - - const extractedDir = path.join(Global.Path.bin, assetName.replace(".zip", "")) - bin = path.join(extractedDir, "bin", "clangd" + (platform === "win32" ? ".exe" : "")) - - if (!(await Bun.file(bin).exists())) { - log.error("Failed to extract clangd binary") - return - } - - if (platform !== "win32") { - await $`chmod +x ${bin}`.nothrow() - } - - log.info(`installed clangd`, { bin }) } + const ext = process.platform === "win32" ? ".exe" : "" + const direct = path.join(Global.Path.bin, "clangd" + ext) + if (await Bun.file(direct).exists()) { + return { + process: spawn(direct, args, { + cwd: root, + }), + } + } + + const entries = await fs.readdir(Global.Path.bin, { withFileTypes: true }).catch(() => []) + for (const entry of entries) { + if (!entry.isDirectory()) continue + if (!entry.name.startsWith("clangd_")) continue + const candidate = path.join(Global.Path.bin, entry.name, "bin", "clangd" + ext) + if (await Bun.file(candidate).exists()) { + return { + process: spawn(candidate, args, { + cwd: root, + }), + } + } + } + + if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return + log.info("downloading clangd from GitHub releases") + + const releaseResponse = await fetch("https://api.github.com/repos/clangd/clangd/releases/latest") + if (!releaseResponse.ok) { + log.error("Failed to fetch clangd release info") + return + } + + const release: { + tag_name?: string + assets?: { name?: string; browser_download_url?: string }[] + } = await releaseResponse.json() + + const tag = release.tag_name + if (!tag) { + log.error("clangd release did not include a tag name") + return + } + const platform = process.platform + const tokens: Record = { + darwin: "mac", + linux: "linux", + win32: "windows", + } + const token = tokens[platform] + if (!token) { + log.error(`Platform ${platform} is not supported by clangd auto-download`) + return + } + + const assets = release.assets ?? [] + const valid = (item: { name?: string; browser_download_url?: string }) => { + if (!item.name) return false + if (!item.browser_download_url) return false + if (!item.name.includes(token)) return false + return item.name.includes(tag) + } + + const asset = + assets.find((item) => valid(item) && item.name?.endsWith(".zip")) ?? + assets.find((item) => valid(item) && item.name?.endsWith(".tar.xz")) ?? + assets.find((item) => valid(item)) + if (!asset?.name || !asset.browser_download_url) { + log.error("clangd could not match release asset", { tag, platform }) + return + } + + const name = asset.name + const downloadResponse = await fetch(asset.browser_download_url) + if (!downloadResponse.ok) { + log.error("Failed to download clangd") + return + } + + const archive = path.join(Global.Path.bin, name) + const buf = await downloadResponse.arrayBuffer() + if (buf.byteLength === 0) { + log.error("Failed to write clangd archive") + return + } + await Bun.write(archive, buf) + + const zip = name.endsWith(".zip") + const tar = name.endsWith(".tar.xz") + if (!zip && !tar) { + log.error("clangd encountered unsupported asset", { asset: name }) + return + } + + if (zip) { + await $`unzip -o -q ${archive}`.quiet().cwd(Global.Path.bin).nothrow() + } + if (tar) { + await $`tar -xf ${archive}`.cwd(Global.Path.bin).nothrow() + } + await fs.rm(archive, { force: true }) + + const bin = path.join(Global.Path.bin, "clangd_" + tag, "bin", "clangd" + ext) + if (!(await Bun.file(bin).exists())) { + log.error("Failed to extract clangd binary") + return + } + + if (platform !== "win32") { + await $`chmod +x ${bin}`.nothrow() + } + + await fs.unlink(path.join(Global.Path.bin, "clangd")).catch(() => {}) + await fs.symlink(bin, path.join(Global.Path.bin, "clangd")).catch(() => {}) + + log.info(`installed clangd`, { bin }) + return { - process: spawn(bin, ["--background-index", "--clang-tidy"], { + process: spawn(bin, args, { cwd: root, }), } diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 56269395bb..a9be085b9c 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 8739e74e0c..25de575532 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From c02230de4f188a8d5759f45f9fb86b9a78d5330a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 12 Nov 2025 12:05:15 +0000 Subject: [PATCH 17/20] ignore: update download stats 2025-11-12 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index f056a50add..3f8da4f211 100644 --- a/STATS.md +++ b/STATS.md @@ -137,3 +137,4 @@ | 2025-11-09 | 713,462 (+7,427) | 660,459 (+6,970) | 1,373,921 (+14,397) | | 2025-11-10 | 722,288 (+8,826) | 668,225 (+7,766) | 1,390,513 (+16,592) | | 2025-11-11 | 729,769 (+7,481) | 677,501 (+9,276) | 1,407,270 (+16,757) | +| 2025-11-12 | 740,180 (+10,411) | 686,454 (+8,953) | 1,426,634 (+19,364) | From 71fd5966add098c92949da26a07346412ad9b804 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:49:02 -0600 Subject: [PATCH 18/20] fix(desktop): styling tweaks --- packages/desktop/src/components/prompt-input.tsx | 6 +++++- packages/desktop/src/pages/session.tsx | 5 +---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 41ec71cfa3..c48572d766 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -345,7 +345,11 @@ export const PromptInput: Component = (props) => { return (
-
+
0} fallback={
No matching files
}> {(i) => ( diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 00a2f464ad..9c639919f6 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -725,15 +725,12 @@ export default function Page() {
- +
-
-
-
All changes
From 0ccb26df94ed83c5a6492068a7bbe73445e54f0c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 12 Nov 2025 07:03:35 -0600 Subject: [PATCH 19/20] feat(desktop): sticky diff headers --- packages/desktop/src/pages/session.tsx | 41 ++++++++++++++++-------- packages/ui/src/components/accordion.css | 38 +++++++++++++--------- packages/ui/src/styles/theme.css | 4 +-- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 9c639919f6..f16729cc27 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -44,7 +44,7 @@ import { useDragDropContext, } from "@thisbeyond/solid-dnd" import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" -import type { JSX } from "solid-js" +import type { JSX, ParentProps } from "solid-js" import { useSync } from "@/context/sync" import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" import { Markdown } from "@opencode-ai/ui" @@ -477,7 +477,7 @@ export default function Page() { class="flex flex-col items-start self-stretch gap-8 pb-20" > {/* Title */} -
+
{(diff) => ( - +
@@ -549,8 +549,8 @@ export default function Page() {
-
- + + {(diff) => ( - +
@@ -702,7 +702,7 @@ export default function Page() {
-
+ - +
-
All changes
-
+
All changes
+
{(diff) => ( - +
@@ -755,7 +755,7 @@ export default function Page() {
-
+ ) } + +function StickyAccordionHeader(props: ParentProps<{ class?: string }>) { + return ( + + {props.children} + + ) +} diff --git a/packages/ui/src/components/accordion.css b/packages/ui/src/components/accordion.css index 5524838bcc..f949dc9484 100644 --- a/packages/ui/src/components/accordion.css +++ b/packages/ui/src/components/accordion.css @@ -12,9 +12,6 @@ align-items: flex-start; gap: 0px; align-self: stretch; - border: 1px solid var(--border-weak-base); - border-bottom: none; - border-top: none; overflow: clip; [data-slot="accordion-header"] { @@ -36,7 +33,7 @@ user-select: none; background-color: var(--surface-base); - border-bottom: 1px solid var(--border-weak-base); + border: 1px solid var(--border-weak-base); overflow: clip; color: var(--text-strong); transition: background-color 0.15s ease; @@ -62,11 +59,19 @@ } &[data-expanded] { - border: 1px solid var(--border-weak-base); - border-bottom: 1px solid var(--border-weak-base); margin-top: 8px; margin-bottom: 8px; - border-radius: 8px; + + [data-slot="accordion-trigger"] { + border-radius: 8px 8px 0 0; + } + + [data-slot="accordion-content"] { + border: 1px solid var(--border-weak-base); + border-top: none; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + } [data-slot="accordion-item"]:has(+ &) { &[data-closed] { @@ -81,18 +86,23 @@ } & + [data-slot="accordion-item"] { - border-top: 1px solid var(--border-weak-base); - border-top-left-radius: 8px; - border-top-right-radius: 8px; margin-top: 8px; + + [data-slot="accordion-trigger"] { + border-top-left-radius: 8px; + border-top-right-radius: 8px; + } + } + } + + &[data-closed] + &[data-closed] { + [data-slot="accordion-trigger"] { + border-top: none; } } &:first-child { margin-top: 0px; - border-top: 1px solid var(--border-weak-base); - border-top-left-radius: 8px; - border-top-right-radius: 8px; &[data-closed] { [data-slot="accordion-trigger"] { @@ -104,8 +114,6 @@ &:last-child { margin-bottom: 0px; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; &[data-closed] { [data-slot="accordion-trigger"] { diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index f6511e3125..05164092e3 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -77,7 +77,7 @@ --background-weak: var(--smoke-light-3); --background-strong: var(--smoke-light-1); --background-stronger: #fcfcfc; - --surface-base: var(--smoke-light-alpha-2); + --surface-base: var(--smoke-light-3); --base: var(--smoke-light-alpha-2); --surface-base-hover: #0500000f; --surface-base-active: var(--smoke-light-alpha-3); @@ -317,7 +317,7 @@ --background-weak: #1b1818; --background-strong: #151313; --background-stronger: #191515; - --surface-base: var(--smoke-dark-alpha-2); + --surface-base: var(--smoke-dark-3); --base: var(--smoke-dark-alpha-2); --surface-base-hover: #e0b7b716; --surface-base-active: var(--smoke-dark-alpha-3); From a0f469095c590110ce51d371be3edfe7a671f330 Mon Sep 17 00:00:00 2001 From: Sebastian Herrlinger Date: Wed, 12 Nov 2025 15:35:16 +0100 Subject: [PATCH 20/20] upgrade opentui to 0.1.42, fixing some CJK/grapheme issues with prompt extmarks and char corruption --- bun.lock | 20 ++++++++++---------- packages/opencode/package.json | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bun.lock b/bun.lock index b889d4e9d1..3f9916ccd3 100644 --- a/bun.lock +++ b/bun.lock @@ -189,8 +189,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.41", - "@opentui/solid": "0.1.41", + "@opentui/core": "0.1.42", + "@opentui/solid": "0.1.42", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -966,21 +966,21 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.1.41", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.41", "@opentui/core-darwin-x64": "0.1.41", "@opentui/core-linux-arm64": "0.1.41", "@opentui/core-linux-x64": "0.1.41", "@opentui/core-win32-arm64": "0.1.41", "@opentui/core-win32-x64": "0.1.41", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-G1v5ZsE7AozKz38ffsxiMuF3tv7hWc+JgqZTyEEMQ57GmGoBrSTNKdWTBNbHy/V9asteIDdBLJV3h1RJedjDCA=="], + "@opentui/core": ["@opentui/core@0.1.42", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.42", "@opentui/core-darwin-x64": "0.1.42", "@opentui/core-linux-arm64": "0.1.42", "@opentui/core-linux-x64": "0.1.42", "@opentui/core-win32-arm64": "0.1.42", "@opentui/core-win32-x64": "0.1.42", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-oV2xHBB2HaNiGvaV6R0C8GmniNJSsLKop4APq4FrLyCYberc6vZcATSHcA5YT9krdvHbBDOOn9RI2oaVJYRbUQ=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.41", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UZqZBiMHUFpYlozJePtNWdJnnhzJL7IaYSyYQVeUHi+0AH10EzEMASLYlYFRWKofCvVgECm/BIhn9PMGZodCwA=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.42", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sk5b/kh/y8HUJ7stGA5ydkajJX/z2OiGqSm+wn6XIoqdDavxQaFoQOt1PCuCqaxqZWJcXZ6OmISDVagZPUsPuw=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.41", "", { "os": "darwin", "cpu": "x64" }, "sha512-cgbZPAMWwALCHtIj+C2ZUpLdRXFWCF7PJqqN9q+psg2sSXBZRPD3oPvonU9hVordMUKDVTjngsBqNo76mzFZGg=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.42", "", { "os": "darwin", "cpu": "x64" }, "sha512-b0FKTw+t/wlJg4u+wTurWzbQe47gExkjguaGSUua0m0vybrkkvbUvmrADr+yivCjxcPAhSZ3lOOVU3uZuWsNqw=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.41", "", { "os": "linux", "cpu": "arm64" }, "sha512-kKBiuM+tb6OGSWObD6W/0IXwofT6tAvlnWA6zje5j7HUFsoo1I0jzynUGCjzOlytsHU56XVWM5dLYd+t1gMr4w=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.42", "", { "os": "linux", "cpu": "arm64" }, "sha512-Vy8BrjJpv2f56JAsYmv4PkC+2HsCv8Gh0ErrlIJQ8L4h29oWabS44m0uxFdvjuTDgKpCJzOScsxsy1VGzSd9rw=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.41", "", { "os": "linux", "cpu": "x64" }, "sha512-BVjuXPEJdz0nu+sSxF9noP7XCrbE1ZEt5xNcKJ3AvLUCbmwYzV7Z/5hscfa/kJErSln0USpCkixVMpoCrbvlnA=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.42", "", { "os": "linux", "cpu": "x64" }, "sha512-cO+13E1HIAPUdV/DRdKotHFAxsLc+ipbbFKGAuu/msfvywCnnNs86w22yeMg0cEqx7aBocWWT1XfJEHDJLFOqw=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.41", "", { "os": "win32", "cpu": "arm64" }, "sha512-ojGXe1IfT6BrsQxn0wtr3zJIwLqRlABNyHUwPv45qJ/Nwl058ZO40HijjUo7cHKaQzuMJ6uzP1J2yqo3GHn9YQ=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.42", "", { "os": "win32", "cpu": "arm64" }, "sha512-xpLhODjOWh7gMOSrKIldb4v6hR0TGyz6kjckDKwcjUv3LGbLJuSly+3O/zuWWS60dt56G1X4A0OyjWwiGZjc0g=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.41", "", { "os": "win32", "cpu": "x64" }, "sha512-KtDYXdFUHEpbyYUdV3LRctkCC3NIwCMDAnHlzFnbsnwJ4NewM9jUtDGDq9gt8ysK48rotrSwbr9udvGAJJel3g=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.42", "", { "os": "win32", "cpu": "x64" }, "sha512-pao5XdAln93WWPdsTF+V+HccZ5d1ijSmv0OoBbkjkVbP+tiN41yxNqg/7jzW9IiAakYsvmpKV+3ixi/dlBEvOQ=="], - "@opentui/solid": ["@opentui/solid@0.1.41", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.41", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-zmbMKY2X1/GKRsEWy+pjyNfap2Wlj/7RNmk1DXC8fon3exSeLotyC3mjLT1rpZya+l5pVdyFCj1Bjbg82i028Q=="], + "@opentui/solid": ["@opentui/solid@0.1.42", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.42", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-4TNlEtatZ4n9TcKPWSF/EoaPaLmZuFVJ4hHh9wRggNaGrmDlmJ+9N/8oEKXETt+oRDX/1CdowAaTOVfaqb1t6g=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 055ae8fb76..0c033c5b1f 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -54,8 +54,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.41", - "@opentui/solid": "0.1.41", + "@opentui/core": "0.1.42", + "@opentui/solid": "0.1.42", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2",