Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5f03290
feat(tui): click on subagents to open them (#5761)
rgodha24 Dec 19, 2025
2f41d0b
chore: generate
actions-user Dec 19, 2025
4fd576f
fix: better api call error msgs in some cases
rekram1-node Dec 19, 2025
b99afda
tweak: better release notes (grouped changelog) (#5768)
Hona Dec 19, 2025
8717146
ci: better err msg for generate workflow
rekram1-node Dec 19, 2025
0dd716a
fix(desktop): extra reqs
adamdotdevin Dec 19, 2025
7ce898c
fix(desktop): shell mode
adamdotdevin Dec 19, 2025
289f4ab
release: v1.0.169
Dec 19, 2025
7f8e799
tweak: DevEx to run changelog independently (#5774)
Hona Dec 19, 2025
5218e7a
docs(ecosystem): add opencode-zellij-namer plugin (#5771)
24601 Dec 19, 2025
2f6ca95
tauri: remove pinch-to-zoom on window
Brendonovich Dec 19, 2025
0b286f1
chore: generate
actions-user Dec 19, 2025
100c31c
fix: use correct octokit API for PR review comment reactions (#5778)
elithrar Dec 19, 2025
8b5cea7
chore: generate
actions-user Dec 19, 2025
3829056
ci: gemini 3 flash doesnt exist in pinned cicd version (#5776)
Hona Dec 19, 2025
3274a58
ci: only run generate for dev
rekram1-node Dec 19, 2025
26d0280
docs: contributing
rekram1-node Dec 19, 2025
1414642
lsp: add oxlint server (#5570)
Eric162 Dec 19, 2025
6a802c0
feat(tui): implement smooth scrolling for autocomplete dropdown navig…
HelloGGX Dec 19, 2025
d03fac5
Update SolidStart and bring back HttpHeader usage (#5355)
Brendonovich Dec 19, 2025
50a5f6e
Update Nix flake.lock and hashes
actions-user Dec 19, 2025
2646da5
ignore: update download stats 2025-12-19
actions-user Dec 19, 2025
ebfb985
user messages as markdown with toggle
kommander Dec 19, 2025
e561f1a
fix(desktop): don't navigate prompt history if dirty
adamdotdevin Dec 19, 2025
2d814b6
fix(desktop): separate prompt history for shell
adamdotdevin Dec 19, 2025
4f318f9
chore: logging
adamdotdevin Dec 19, 2025
e1ad2a3
fix(desktop): error handling
adamdotdevin Dec 19, 2025
55d62fb
release: v1.0.170
Dec 19, 2025
a9bf79f
sync: merge upstream v1.0.170 into integration
opencode-agent[bot] Dec 19, 2025
ad58113
sync: record last synced tag v1.0.170
opencode-agent[bot] Dec 19, 2025
314359e
chore: generate
actions-user Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/last-synced-tag
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.169
v1.0.170
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:

- name: Install OpenCode
if: inputs.bump || inputs.version
run: bun i -g opencode-ai@1.0.143
run: bun i -g opencode-ai@1.0.169

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Want to take on an issue? Leave a comment and a maintainer may assign it to you
- `packages/plugin`: Source for `@opencode-ai/plugin`

> [!NOTE]
> After touching `packages/opencode/src/server/server.ts`, run "./packages/sdk/js/script/build.ts" to regenerate the JS sdk.
> If you make changes to the API or SDK (e.g. `packages/opencode/src/server/server.ts`), run `./script/generate.ts` to regenerate the SDK and related files.

Please try to follow the [style guide](./STYLE_GUIDE.md)

Expand Down
1 change: 1 addition & 0 deletions STATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,4 @@
| 2025-12-16 | 1,120,477 (+26,845) | 1,078,022 (+18,944) | 2,198,499 (+45,789) |
| 2025-12-17 | 1,151,067 (+30,590) | 1,097,661 (+19,639) | 2,248,728 (+50,229) |
| 2025-12-18 | 1,178,658 (+27,591) | 1,113,418 (+15,757) | 2,292,076 (+43,348) |
| 2025-12-19 | 1,203,485 (+24,827) | 1,129,698 (+16,280) | 2,333,183 (+41,107) |
89 changes: 24 additions & 65 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion nix/hashes.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"nodeModules": "sha256-U56rAkhKAhZKDEec05Mxj359wjpT03od26tosCjrj9A="
"nodeModules": "sha256-oT1WPPR1sHBhQcJaFL+mod5l3+V8O3uPKJUdrcfTst0="
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"vite": "7.1.4",
"@solidjs/meta": "0.29.4",
"@solidjs/router": "0.15.4",
"@solidjs/start": "https://pkg.pr.new/@solidjs/start@dfb2020",
"@solidjs/start": "https://pkg.pr.new/@solidjs/start@57aeb22",
"solid-js": "1.9.10",
"vite-plugin-solid": "2.11.10"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/console/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.0.169-1",
"version": "1.0.170",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
Expand Down
4 changes: 2 additions & 2 deletions packages/console/app/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "./index.css"
import { Title, Meta, Link } from "@solidjs/meta"
// import { HttpHeader } from "@solidjs/start"
import { HttpHeader } from "@solidjs/start"
import video from "../asset/lander/opencode-min.mp4"
import videoPoster from "../asset/lander/opencode-poster.png"
import { IconCopy, IconCheck } from "../component/icon"
Expand Down Expand Up @@ -42,7 +42,7 @@ export default function Home() {

return (
<main data-page="opencode">
{/*<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />*/}
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
<Title>OpenCode | The open source AI coding agent</Title>
<Link rel="canonical" href={config.baseUrl} />
<Meta property="og:image" content="/social-share.png" />
Expand Down
4 changes: 2 additions & 2 deletions packages/console/app/src/routes/zen/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "./index.css"
import { createAsync, query, redirect } from "@solidjs/router"
import { Title, Meta, Link } from "@solidjs/meta"
// import { HttpHeader } from "@solidjs/start"
import { HttpHeader } from "@solidjs/start"
import zenLogoLight from "../../asset/zen-ornate-light.svg"
import { config } from "~/config"
import zenLogoDark from "../../asset/zen-ornate-dark.svg"
Expand Down Expand Up @@ -30,7 +30,7 @@ export default function Home() {
const loggedin = createAsync(() => checkLoggedIn())
return (
<main data-page="zen">
{/*<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />*/}
<HttpHeader name="Cache-Control" value="public, max-age=1, s-maxage=3600, stale-while-revalidate=86400" />
<Title>OpenCode Zen | A curated set of reliable optimized models for coding agents</Title>
<Link rel="canonical" href={`${config.baseUrl}/zen`} />
<Meta property="og:image" content="/social-share-zen.png" />
Expand Down
2 changes: 1 addition & 1 deletion packages/console/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.0.169-1",
"version": "1.0.170",
"private": true,
"type": "module",
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/console/function/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.0.169-1",
"version": "1.0.170",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/console/mail/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.0.169-1",
"version": "1.0.170",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
"version": "1.0.169-1",
"version": "1.0.170",
"description": "",
"type": "module",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function App() {
return (
<MetaProvider>
<Font />
<ErrorBoundary fallback={ErrorPage}>
<ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
<DialogProvider>
<MarkedProvider>
<DiffComponentProvider component={Diff}>
Expand Down
31 changes: 26 additions & 5 deletions packages/desktop/src/components/prompt-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
imageAttachments: ImageAttachmentPart[]
mode: "normal" | "shell"
applyingHistory: boolean
userHasEdited: boolean
}>({
popover: null,
historyIndex: -1,
Expand All @@ -111,6 +112,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
imageAttachments: [],
mode: "normal",
applyingHistory: false,
userHasEdited: false,
})

const MAX_HISTORY = 100
Expand All @@ -122,6 +124,14 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
entries: [],
}),
)
const [shellHistory, setShellHistory] = persisted(
"prompt-history-shell.v1",
createStore<{
entries: Prompt[]
}>({
entries: [],
}),
)

const clonePromptParts = (prompt: Prompt): Prompt =>
prompt.map((part) => {
Expand All @@ -139,6 +149,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
const applyHistoryPrompt = (p: Prompt, position: "start" | "end") => {
const length = position === "start" ? 0 : promptLength(p)
setStore("applyingHistory", true)
setStore("userHasEdited", false)
prompt.set(p, length)
requestAnimationFrame(() => {
editorRef.focus()
Expand Down Expand Up @@ -440,6 +451,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {

if (shouldReset) {
setStore("popover", null)
setStore("userHasEdited", false)
if (store.historyIndex >= 0 && !store.applyingHistory) {
setStore("historyIndex", -1)
setStore("savedPrompt", null)
Expand Down Expand Up @@ -474,6 +486,10 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
setStore("savedPrompt", null)
}

if (!store.applyingHistory) {
setStore("userHasEdited", true)
}

prompt.set(rawParts, cursorPosition)
}

Expand Down Expand Up @@ -547,25 +563,29 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
sessionID: params.id!,
})

const addToHistory = (prompt: Prompt) => {
const addToHistory = (prompt: Prompt, mode: "normal" | "shell") => {
const text = prompt
.map((p) => ("content" in p ? p.content : ""))
.join("")
.trim()
if (!text) return

const entry = clonePromptParts(prompt)
const lastEntry = history.entries[0]
const currentHistory = mode === "shell" ? shellHistory : history
const setCurrentHistory = mode === "shell" ? setShellHistory : setHistory
const lastEntry = currentHistory.entries[0]
if (lastEntry) {
const lastText = lastEntry.map((p) => ("content" in p ? p.content : "")).join("")
if (lastText === text) return
}

setHistory("entries", (entries) => [entry, ...entries].slice(0, MAX_HISTORY))
setCurrentHistory("entries", (entries) => [entry, ...entries].slice(0, MAX_HISTORY))
}

const navigateHistory = (direction: "up" | "down") => {
const entries = history.entries
if (store.userHasEdited) return false

const entries = store.mode === "shell" ? shellHistory.entries : history.entries
const current = store.historyIndex

if (direction === "up") {
Expand Down Expand Up @@ -693,9 +713,10 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
return
}

addToHistory(currentPrompt)
addToHistory(currentPrompt, store.mode)
setStore("historyIndex", -1)
setStore("savedPrompt", null)
setStore("userHasEdited", false)

let existing = info()
if (!existing) {
Expand Down
12 changes: 5 additions & 7 deletions packages/desktop/src/context/global-sdk.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { createGlobalEmitter } from "@solid-primitives/event-bus"
import { onCleanup } from "solid-js"
import { usePlatform } from "./platform"

export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleContext({
name: "GlobalSDK",
init: (props: { url: string }) => {
const abort = new AbortController()
const platform = usePlatform()

const sdk = createOpencodeClient({
baseUrl: props.url,
signal: abort.signal,
signal: AbortSignal.timeout(1000 * 60 * 10),
fetch: platform.fetch,
throwOnError: true,
})

Expand All @@ -30,10 +32,6 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
console.error("Event stream error:", error)
})

onCleanup(() => {
abort.abort()
})

return { url: props.url, client: sdk, event: emitter }
},
})
5 changes: 4 additions & 1 deletion packages/desktop/src/context/global-sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { Binary } from "@opencode-ai/util/binary"
import { useGlobalSDK } from "./global-sdk"
import { ErrorPage, type InitError } from "../pages/error"
import { createContext, useContext, onMount, type ParentProps, Switch, Match } from "solid-js"
import { showToast } from "@opencode-ai/ui/toast"
import { getFilename } from "@opencode-ai/util/path"

type State = {
ready: boolean
Expand Down Expand Up @@ -118,7 +120,8 @@ function createGlobalSync() {
})
.catch((err) => {
console.error("Failed to load sessions", err)
setGlobalStore("error", err)
const project = getFilename(directory)
showToast({ title: `Failed to load sessions for ${project}`, description: err.message })
})
}

Expand Down
12 changes: 9 additions & 3 deletions packages/desktop/src/context/platform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ export type Platform = {
/** Platform discriminator */
platform: "web" | "tauri"

/** Open a URL in the default browser */
openLink(url: string): void

/** Restart the app */
restart(): Promise<void>

/** Open native directory picker dialog (Tauri only) */
openDirectoryPickerDialog?(opts?: { title?: string; multiple?: boolean }): Promise<string | string[] | null>

Expand All @@ -14,9 +20,6 @@ export type Platform = {
/** Save file picker dialog (Tauri only) */
saveFilePickerDialog?(opts?: { title?: string; defaultPath?: string }): Promise<string | null>

/** Open a URL in the default browser */
openLink(url: string): void

/** Storage mechanism, defaults to localStorage */
storage?: (name?: string) => SyncStorage | AsyncStorage

Expand All @@ -25,6 +28,9 @@ export type Platform = {

/** Install updates (Tauri only) */
update?(): Promise<void>

/** Fetch override */
fetch?: typeof fetch
}

export const { use: usePlatform, provider: PlatformProvider } = createSimpleContext({
Expand Down
11 changes: 4 additions & 7 deletions packages/desktop/src/context/sdk.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2/client"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { createGlobalEmitter } from "@solid-primitives/event-bus"
import { onCleanup } from "solid-js"
import { useGlobalSDK } from "./global-sdk"
import { usePlatform } from "./platform"

export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
name: "SDK",
init: (props: { directory: string }) => {
const platform = usePlatform()
const globalSDK = useGlobalSDK()
const abort = new AbortController()
const sdk = createOpencodeClient({
baseUrl: globalSDK.url,
signal: abort.signal,
signal: AbortSignal.timeout(1000 * 60 * 10),
fetch: platform.fetch,
directory: props.directory,
throwOnError: true,
})
Expand All @@ -24,10 +25,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
emitter.emit(event.type, event)
})

onCleanup(() => {
abort.abort()
})

return { directory: props.directory, client: sdk, event: emitter, url: globalSDK.url }
},
})
3 changes: 3 additions & 0 deletions packages/desktop/src/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const platform: Platform = {
openLink(url: string) {
window.open(url, "_blank")
},
restart: async () => {
window.location.reload()
},
}

render(
Expand Down
Loading