From 94c128f73b05bb4b14134974d9db8eb7eb671b92 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 10 Mar 2026 16:56:30 +0000 Subject: [PATCH 01/15] chore: generate --- .../snapshot.json | 117 +++++------------- packages/opencode/src/account/repo.ts | 10 +- packages/opencode/src/account/service.ts | 4 +- packages/opencode/src/cli/cmd/account.ts | 4 +- packages/opencode/test/cli/import.test.ts | 4 +- packages/opencode/tsconfig.json | 12 +- 6 files changed, 50 insertions(+), 101 deletions(-) diff --git a/packages/opencode/migration/20260309230000_move_org_to_state/snapshot.json b/packages/opencode/migration/20260309230000_move_org_to_state/snapshot.json index 37b9eacacc..488ecefffb 100644 --- a/packages/opencode/migration/20260309230000_move_org_to_state/snapshot.json +++ b/packages/opencode/migration/20260309230000_move_org_to_state/snapshot.json @@ -2,10 +2,7 @@ "version": "7", "dialect": "sqlite", "id": "fb311f30-9948-4131-b15c-7d308478a878", - "prevIds": [ - "325559b7-104f-4d2a-a02c-934cfad7cfcc", - "4ec9de62-88a7-4bec-91cc-0a759e84db21" - ], + "prevIds": ["325559b7-104f-4d2a-a02c-934cfad7cfcc", "4ec9de62-88a7-4bec-91cc-0a759e84db21"], "ddl": [ { "name": "account_state", @@ -892,13 +889,9 @@ "table": "session_share" }, { - "columns": [ - "active_account_id" - ], + "columns": ["active_account_id"], "tableTo": "account", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "SET NULL", "nameExplicit": false, @@ -907,13 +900,9 @@ "table": "account_state" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -922,13 +911,9 @@ "table": "workspace" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -937,13 +922,9 @@ "table": "message" }, { - "columns": [ - "message_id" - ], + "columns": ["message_id"], "tableTo": "message", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -952,13 +933,9 @@ "table": "part" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -967,13 +944,9 @@ "table": "permission" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "tableTo": "project", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -982,13 +955,9 @@ "table": "session" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -997,13 +966,9 @@ "table": "todo" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "tableTo": "session", - "columnsTo": [ - "id" - ], + "columnsTo": ["id"], "onUpdate": "NO ACTION", "onDelete": "CASCADE", "nameExplicit": false, @@ -1012,101 +977,77 @@ "table": "session_share" }, { - "columns": [ - "email", - "url" - ], + "columns": ["email", "url"], "nameExplicit": false, "name": "control_account_pk", "entityType": "pks", "table": "control_account" }, { - "columns": [ - "session_id", - "position" - ], + "columns": ["session_id", "position"], "nameExplicit": false, "name": "todo_pk", "entityType": "pks", "table": "todo" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "account_state_pk", "table": "account_state", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "account_pk", "table": "account", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "workspace_pk", "table": "workspace", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "project_pk", "table": "project", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "message_pk", "table": "message", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "part_pk", "table": "part", "entityType": "pks" }, { - "columns": [ - "project_id" - ], + "columns": ["project_id"], "nameExplicit": false, "name": "permission_pk", "table": "permission", "entityType": "pks" }, { - "columns": [ - "id" - ], + "columns": ["id"], "nameExplicit": false, "name": "session_pk", "table": "session", "entityType": "pks" }, { - "columns": [ - "session_id" - ], + "columns": ["session_id"], "nameExplicit": false, "name": "session_share_pk", "table": "session_share", @@ -1212,4 +1153,4 @@ } ], "renames": [] -} \ No newline at end of file +} diff --git a/packages/opencode/src/account/repo.ts b/packages/opencode/src/account/repo.ts index ba71abe342..65f56727b9 100644 --- a/packages/opencode/src/account/repo.ts +++ b/packages/opencode/src/account/repo.ts @@ -69,7 +69,15 @@ export class AccountRepo extends ServiceMap.Service< db((db) => current(db)).pipe(Effect.map((row) => (row ? Option.some(decodeAccount(row)) : Option.none()))), ), - list: Effect.fn("AccountRepo.list")(() => db((db) => db.select().from(AccountTable).all().map((row) => decodeAccount({ ...row, active_org_id: null })))), + list: Effect.fn("AccountRepo.list")(() => + db((db) => + db + .select() + .from(AccountTable) + .all() + .map((row) => decodeAccount({ ...row, active_org_id: null })), + ), + ), remove: Effect.fn("AccountRepo.remove")((accountID: AccountID) => db((db) => diff --git a/packages/opencode/src/account/service.ts b/packages/opencode/src/account/service.ts index 68ea9dbdec..c57bb459a0 100644 --- a/packages/opencode/src/account/service.ts +++ b/packages/opencode/src/account/service.ts @@ -346,7 +346,9 @@ export class AccountService extends ServiceMap.Service< const expiry = now + (parsed.expires_in ?? 0) * 1000 const refresh = parsed.refresh_token ?? "" if (!refresh) { - yield* Effect.logWarning("Server did not return a refresh token — session may expire without ability to refresh") + yield* Effect.logWarning( + "Server did not return a refresh token — session may expire without ability to refresh", + ) } yield* repo.persistAccount({ diff --git a/packages/opencode/src/cli/cmd/account.ts b/packages/opencode/src/cli/cmd/account.ts index 51cf2b138c..7e9f893a8f 100644 --- a/packages/opencode/src/cli/cmd/account.ts +++ b/packages/opencode/src/cli/cmd/account.ts @@ -75,9 +75,7 @@ const logoutEffect = Effect.fn("logout")(function* (email?: string) { const server = UI.Style.TEXT_DIM + a.url + UI.Style.TEXT_NORMAL return { value: a, - label: isActive - ? `${a.email} ${server}` + UI.Style.TEXT_DIM + " (active)" - : `${a.email} ${server}`, + label: isActive ? `${a.email} ${server}` + UI.Style.TEXT_DIM + " (active)" : `${a.email} ${server}`, } }) diff --git a/packages/opencode/test/cli/import.test.ts b/packages/opencode/test/cli/import.test.ts index 922c08114b..d7c0241e6b 100644 --- a/packages/opencode/test/cli/import.test.ts +++ b/packages/opencode/test/cli/import.test.ts @@ -24,9 +24,7 @@ test("only attaches share auth headers for same-origin URLs", () => { expect(shouldAttachShareAuthHeaders("https://control.example.com/share/abc", "https://control.example.com")).toBe( true, ) - expect( - shouldAttachShareAuthHeaders("https://other.example.com/share/abc", "https://control.example.com"), - ).toBe(false) + expect(shouldAttachShareAuthHeaders("https://other.example.com/share/abc", "https://control.example.com")).toBe(false) expect(shouldAttachShareAuthHeaders("https://control.example.com:443/share/abc", "https://control.example.com")).toBe( true, ) diff --git a/packages/opencode/tsconfig.json b/packages/opencode/tsconfig.json index 44335bd80d..ff9886313a 100644 --- a/packages/opencode/tsconfig.json +++ b/packages/opencode/tsconfig.json @@ -12,10 +12,12 @@ "@/*": ["./src/*"], "@tui/*": ["./src/cli/cmd/tui/*"] }, - "plugins": [{ - "name": "@effect/language-service", - "transform": "@effect/language-service/transform", - "namespaceImportPackages": ["effect", "@effect/*"] - }] + "plugins": [ + { + "name": "@effect/language-service", + "transform": "@effect/language-service/transform", + "namespaceImportPackages": ["effect", "@effect/*"] + } + ] } } From bb232247d094b22d497a036c21d4c4a722700a38 Mon Sep 17 00:00:00 2001 From: Dax Date: Tue, 10 Mar 2026 13:11:36 -0400 Subject: [PATCH 02/15] Fix ESM imports for @opencode-ai/plugin (#16916) --- packages/plugin/src/example.ts | 4 ++-- packages/plugin/src/index.ts | 6 +++--- packages/plugin/tsconfig.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/plugin/src/example.ts b/packages/plugin/src/example.ts index 94745a37b7..1cf042fe96 100644 --- a/packages/plugin/src/example.ts +++ b/packages/plugin/src/example.ts @@ -1,5 +1,5 @@ -import { Plugin } from "./index" -import { tool } from "./tool" +import { Plugin } from "./index.js" +import { tool } from "./tool.js" export const ExamplePlugin: Plugin = async (ctx) => { return { diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 76370d1d5a..b78bcae177 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -12,10 +12,10 @@ import type { Config, } from "@opencode-ai/sdk" -import type { BunShell } from "./shell" -import { type ToolDefinition } from "./tool" +import type { BunShell } from "./shell.js" +import { type ToolDefinition } from "./tool.js" -export * from "./tool" +export * from "./tool.js" export type ProviderContext = { source: "env" | "config" | "custom" | "api" diff --git a/packages/plugin/tsconfig.json b/packages/plugin/tsconfig.json index 58072c81c9..1173818783 100644 --- a/packages/plugin/tsconfig.json +++ b/packages/plugin/tsconfig.json @@ -3,9 +3,9 @@ "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { "outDir": "dist", - "module": "preserve", + "module": "nodenext", "declaration": true, - "moduleResolution": "bundler", + "moduleResolution": "nodenext", "lib": ["es2022", "dom", "dom.iterable"] }, "include": ["src"] From 490615169e6717daab641fed827c21b11ef84a85 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 10 Mar 2026 17:14:55 +0000 Subject: [PATCH 03/15] chore: update nix node_modules hashes --- nix/hashes.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/hashes.json b/nix/hashes.json index d4146be6b7..153f78ac6d 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-duBedS4ZTc1as03OM0KB9mKKU21Cywv4o9GHwQZv6Ts=", - "aarch64-linux": "sha256-juvQfuNBqqzeB/TIY9PuUDqgpsdyI54ImowjQLrNhns=", - "aarch64-darwin": "sha256-kKgcuEN1oJqHJc+sGjcZ4INWvbZczSTDJ8VHIWAquD4=", - "x86_64-darwin": "sha256-hXkFWOL4wi9s8HSrChpqtH4PKSNzbzVgU+0GbAxEUT4=" + "x86_64-linux": "sha256-dhL4YeSi4Lm9yDp919Fx7N2hyLUbZQa2qWoCf/50ce8=", + "aarch64-linux": "sha256-//YxCsrvYlxuvd0MtFFO+pLxjmuemyrvGzSIPxzO+rA=", + "aarch64-darwin": "sha256-c65kSWteQNaBcQUsjbXNqT61vt98JPNYo9yMNvUygCw=", + "x86_64-darwin": "sha256-hlTzEFv3nZHwlDXU65LfMC+NaqYjjyZqagdJ366CNxY=" } } From 85afaaa13d693f400d8ec8e257fec086a58b68c1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 10 Mar 2026 07:33:54 -0500 Subject: [PATCH 04/15] fix(app): terminal focus issues and jank --- .../app/src/pages/session/terminal-panel.tsx | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/packages/app/src/pages/session/terminal-panel.tsx b/packages/app/src/pages/session/terminal-panel.tsx index 8fd652e903..19a656b530 100644 --- a/packages/app/src/pages/session/terminal-panel.tsx +++ b/packages/app/src/pages/session/terminal-panel.tsx @@ -1,4 +1,4 @@ -import { For, Show, createEffect, createMemo, on } from "solid-js" +import { For, Show, createEffect, createMemo, on, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { createMediaQuery } from "@solid-primitives/media" import { useParams } from "@solidjs/router" @@ -17,7 +17,7 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useTerminal, type LocalPTY } from "@/context/terminal" import { terminalTabLabel } from "@/pages/session/terminal-label" -import { createPresence, createSizing, focusTerminalById } from "@/pages/session/helpers" +import { createSizing, focusTerminalById } from "@/pages/session/helpers" import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff" export function TerminalPanel() { @@ -33,7 +33,6 @@ export function TerminalPanel() { const opened = createMemo(() => view().terminal.opened()) const open = createMemo(() => isDesktop() && opened()) - const panel = createPresence(open) const size = createSizing() const height = createMemo(() => layout.terminal.height()) const close = () => view().terminal.close() @@ -66,21 +65,42 @@ export function TerminalPanel() { ), ) + const focus = (id: string) => { + focusTerminalById(id) + + const frame = requestAnimationFrame(() => { + if (!open()) return + if (terminal.active() !== id) return + focusTerminalById(id) + }) + + const timers = [120, 240].map((ms) => + window.setTimeout(() => { + if (!open()) return + if (terminal.active() !== id) return + focusTerminalById(id) + }, ms), + ) + + return () => { + cancelAnimationFrame(frame) + for (const timer of timers) clearTimeout(timer) + } + } + createEffect( on( - () => terminal.active(), - (activeId) => { - if (!activeId || !panel.open()) return - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur() - } - setTimeout(() => focusTerminalById(activeId), 0) + () => [open(), terminal.active()] as const, + ([next, id]) => { + if (!next || !id) return + const stop = focus(id) + onCleanup(stop) }, ), ) createEffect(() => { - if (panel.open()) return + if (open()) return const active = document.activeElement if (!(active instanceof HTMLElement)) return if (!root?.contains(active)) return @@ -138,30 +158,38 @@ export function TerminalPanel() { const activeId = terminal.active() if (!activeId) return - setTimeout(() => { + requestAnimationFrame(() => { + if (terminal.active() !== activeId) return focusTerminalById(activeId) - }, 0) + }) } return ( - +
-
+
size.start()}> Date: Tue, 10 Mar 2026 11:29:57 -0500 Subject: [PATCH 05/15] fix(app): terminal jank --- .../src/components/session/session-header.tsx | 75 +++-- packages/app/src/components/terminal.tsx | 5 +- packages/app/src/pages/session.tsx | 11 +- .../app/src/pages/session/terminal-panel.tsx | 292 +++++++++--------- 4 files changed, 208 insertions(+), 175 deletions(-) diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 9b4551584c..97f0530e98 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -21,6 +21,8 @@ import { useLayout } from "@/context/layout" import { usePlatform } from "@/context/platform" import { useServer } from "@/context/server" import { useSync } from "@/context/sync" +import { useTerminal } from "@/context/terminal" +import { focusTerminalById } from "@/pages/session/helpers" import { decode64 } from "@/utils/base64" import { Persist, persisted } from "@/utils/persist" import { StatusPopover } from "../status-popover" @@ -229,6 +231,7 @@ export function SessionHeader() { const sync = useSync() const platform = usePlatform() const language = useLanguage() + const terminal = useTerminal() const projectDirectory = createMemo(() => decode64(params.dir) ?? "") const project = createMemo(() => { @@ -296,6 +299,16 @@ export function SessionHeader() { ] as const }) + const toggleTerminal = () => { + const next = !view().terminal.opened() + view().terminal.toggle() + if (!next) return + + const id = terminal.active() + if (!id) return + focusTerminalById(id) + } + const [prefs, setPrefs] = persisted(Persist.global("open.app"), createStore({ app: "finder" as OpenApp })) const [menu, setMenu] = createStore({ open: false }) const [openRequest, setOpenRequest] = createStore({ @@ -617,39 +630,39 @@ export function SessionHeader() {
-