diff --git a/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts b/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts index 611db406b5..0b8b58fc7f 100644 --- a/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts +++ b/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts @@ -195,6 +195,10 @@ export function resolveZedDbPath() { return candidates.find((item) => isFile(item)) } +export function isZedTerminal() { + return process.env.ZED_TERM === "true" || process.env.TERM_PROGRAM?.toLowerCase() === "zed" +} + function isFile(item: string) { try { return Filesystem.stat(item)?.isFile() === true diff --git a/packages/opencode/src/cli/cmd/tui/context/editor.ts b/packages/opencode/src/cli/cmd/tui/context/editor.ts index ea7fd5810b..38cc52fe06 100644 --- a/packages/opencode/src/cli/cmd/tui/context/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/context/editor.ts @@ -6,7 +6,7 @@ import { createStore } from "solid-js/store" import { Option, Schema, SchemaGetter } from "effect" import { isRecord } from "@/util/record" import { createSimpleContext } from "./helper" -import { resolveZedDbPath, resolveZedSelection } from "./editor-zed" +import { isZedTerminal, resolveZedDbPath, resolveZedSelection } from "./editor-zed" const MCP_PROTOCOL_VERSION = "2025-11-25" @@ -173,6 +173,12 @@ export const { use: useEditorContext, provider: EditorContextProvider } = create const connection = resolveEditorConnection(directory) if (!connection) { + if (!isZedTerminal()) { + setStore("status", "disabled") + scheduleReconnect() + return + } + const dbPath = resolveZedDbPath() if (!dbPath) { setStore("status", "disabled") @@ -311,7 +317,7 @@ export const { use: useEditorContext, provider: EditorContextProvider } = create return { enabled() { - return Boolean(resolveEditorConnection(directory) || resolveZedDbPath()) + return Boolean(resolveEditorConnection(directory) || (isZedTerminal() && resolveZedDbPath())) }, connected() { return store.status === "connected" diff --git a/packages/opencode/src/effect/config-service.ts b/packages/opencode/src/effect/config-service.ts index 75a6ad90e4..3c13afc12a 100644 --- a/packages/opencode/src/effect/config-service.ts +++ b/packages/opencode/src/effect/config-service.ts @@ -48,12 +48,14 @@ export const Service = } static get defaultLayer() { + const tag = this return Layer.effect( - this, - Config.all(fields).pipe( + tag, + Effect.gen(function* () { + const config = yield* Config.all(fields) // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Config.all preserves the field shape, but its conditional return type also supports iterable inputs. - Effect.map((config) => this.of(config as Shape)), - ), + return tag.of(config as Shape) + }), ) } } diff --git a/packages/opencode/test/cli/tui/editor-context-zed.test.ts b/packages/opencode/test/cli/tui/editor-context-zed.test.ts index 0287b0910f..f16a00af65 100644 --- a/packages/opencode/test/cli/tui/editor-context-zed.test.ts +++ b/packages/opencode/test/cli/tui/editor-context-zed.test.ts @@ -2,10 +2,25 @@ import { Database } from "bun:sqlite" import { mkdir, symlink } from "node:fs/promises" import os from "node:os" import path from "node:path" -import { expect, spyOn, test } from "bun:test" -import { offsetToPosition, resolveZedDbPath, resolveZedSelection } from "../../../src/cli/cmd/tui/context/editor-zed" +import { afterEach, expect, spyOn, test } from "bun:test" +import { + isZedTerminal, + offsetToPosition, + resolveZedDbPath, + resolveZedSelection, +} from "../../../src/cli/cmd/tui/context/editor-zed" import { tmpdir } from "../../fixture/fixture" +const originalZedTerm = process.env.ZED_TERM +const originalTermProgram = process.env.TERM_PROGRAM + +afterEach(() => { + if (originalZedTerm === undefined) delete process.env.ZED_TERM + else process.env.ZED_TERM = originalZedTerm + if (originalTermProgram === undefined) delete process.env.TERM_PROGRAM + else process.env.TERM_PROGRAM = originalTermProgram +}) + type ZedFixtureOptions = { workspacePaths?: string | null itemKind?: string @@ -85,6 +100,19 @@ test("resolveZedDbPath skips candidates that cannot be stated", async () => { } }) +test("isZedTerminal only returns true for Zed terminal environments", () => { + delete process.env.ZED_TERM + delete process.env.TERM_PROGRAM + expect(isZedTerminal()).toBeFalse() + + process.env.ZED_TERM = "true" + expect(isZedTerminal()).toBeTrue() + + process.env.ZED_TERM = "false" + process.env.TERM_PROGRAM = "zed" + expect(isZedTerminal()).toBeTrue() +}) + test("resolveZedSelection returns active editor selection", async () => { await using tmp = await tmpdir() const fixture = await writeZedFixture(tmp.path)