diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx
index 12a19af0a1f..9ef40e5addf 100644
--- a/packages/opencode/src/cli/cmd/tui/app.tsx
+++ b/packages/opencode/src/cli/cmd/tui/app.tsx
@@ -13,7 +13,6 @@ import { LocalProvider, useLocal } from "@tui/context/local"
import { DialogModel, useConnected } from "@tui/component/dialog-model"
import { DialogMcp } from "@tui/component/dialog-mcp"
import { DialogTools } from "@tui/component/dialog-tools"
-import { DialogIde } from "@tui/component/dialog-ide"
import { DialogStatus } from "@tui/component/dialog-status"
import { DialogThemeList } from "@tui/component/dialog-theme-list"
import { DialogSpinnerList, DialogSpinnerInterval } from "@tui/component/dialog-spinner"
@@ -378,14 +377,6 @@ function App() {
dialog.replace(() => )
},
},
- {
- title: "Toggle IDEs",
- value: "ide.list",
- category: "Agent",
- onSelect: () => {
- dialog.replace(() => )
- },
- },
{
title: "Agent cycle",
value: "agent.cycle",
diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx
deleted file mode 100644
index 8998f6f5a0b..00000000000
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-ide.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { createMemo, createSignal } from "solid-js"
-import { useLocal } from "@tui/context/local"
-import { useSync } from "@tui/context/sync"
-import { map, pipe, entries, sortBy } from "remeda"
-import { DialogSelect, type DialogSelectRef, type DialogSelectOption } from "@tui/ui/dialog-select"
-import { useTheme } from "../context/theme"
-import { Keybind } from "@/util/keybind"
-import { TextAttributes } from "@opentui/core"
-
-function Status(props: { connected: boolean; loading: boolean }) {
- const { theme } = useTheme()
- if (props.loading) {
- return ⋯ Loading
- }
- if (props.connected) {
- return ✓ Connected
- }
- return ○ Disconnected
-}
-
-export function DialogIde() {
- const local = useLocal()
- const sync = useSync()
- const [, setRef] = createSignal>()
- const [loading, setLoading] = createSignal(null)
-
- const options = createMemo(() => {
- const ideData = sync.data.ide
- const loadingIde = loading()
- const projectDir = process.cwd()
-
- return pipe(
- ideData ?? {},
- entries(),
- sortBy(
- ([key]) => {
- const folders = local.ide.getWorkspaceFolders(key)
- // Exact match - highest priority
- if (folders.some((folder: string) => folder === projectDir)) return 0
- // IDE workspace contains current directory (we're in a subdirectory of IDE workspace)
- if (folders.some((folder: string) => projectDir.startsWith(folder + "/"))) return 1
- return 2
- },
- ([, status]) => status.name,
- ),
- map(([key, status]) => {
- return {
- value: key,
- title: status.name,
- description: local.ide.getWorkspaceFolders(key)[0],
- footer: ,
- category: undefined,
- }
- }),
- )
- })
-
- const keybinds = createMemo(() => [
- {
- keybind: Keybind.parse("space")[0],
- title: "toggle",
- onTrigger: async (option: DialogSelectOption) => {
- if (loading() !== null) return
-
- setLoading(option.value)
- try {
- await local.ide.toggle(option.value)
- } finally {
- setLoading(null)
- }
- },
- },
- ])
-
- return {}} />
-}
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 d5a3bf1eb82..8f679ad022d 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx
@@ -436,11 +436,6 @@ export function Autocomplete(props: {
description: "list tools",
onSelect: () => command.trigger("tool.list"),
},
- {
- display: "/ide",
- description: "toggle IDEs",
- onSelect: () => command.trigger("ide.list"),
- },
{
display: "/theme",
description: "toggle theme",
diff --git a/packages/opencode/src/cli/cmd/tui/context/local.tsx b/packages/opencode/src/cli/cmd/tui/context/local.tsx
index ef9c4b7c93b..ceb052bad75 100644
--- a/packages/opencode/src/cli/cmd/tui/context/local.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/local.tsx
@@ -1,4 +1,4 @@
-import { createStore, reconcile } from "solid-js/store"
+import { createStore } from "solid-js/store"
import { batch, createEffect, createMemo } from "solid-js"
import { useSync } from "@tui/context/sync"
import { useTheme } from "@tui/context/theme"
@@ -12,7 +12,6 @@ import { Provider } from "@/provider/provider"
import { useArgs } from "./args"
import { useSDK } from "./sdk"
import { RGBA } from "@opentui/core"
-import { Ide } from "@/ide"
export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
name: "Local",
@@ -39,7 +38,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const [agentStore, setAgentStore] = createStore<{
current: string
}>({
- current: agents().find((x) => x.default)?.name ?? agents()[0].name,
+ current: agents()[0]?.name ?? "default",
})
const { theme } = useTheme()
const colors = createMemo(() => [
@@ -366,54 +365,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
},
}
- const ide = {
- isConnected(name: string) {
- const status = sync.data.ide[name]
- return status?.status === "connected"
- },
- getWorkspaceFolders(name: string) {
- const status = sync.data.ide[name]
- if (status && "workspaceFolders" in status && status.workspaceFolders) {
- return status.workspaceFolders
- }
- return []
- },
- async toggle(name: string) {
- const current = sync.data.ide[name]
- if (current?.status === "connected") {
- await Ide.disconnect()
- } else {
- await Ide.connect(name)
- }
- const status = await Ide.status()
- sync.set("ide", reconcile(status))
- },
- }
-
- const selection = iife(() => {
- const [selStore, setSelStore] = createStore<{
- current: Ide.Selection | null
- }>({ current: null })
-
- sdk.event.on(Ide.Event.SelectionChanged.type, async (evt) => {
- setSelStore("current", evt.properties.selection)
- // Refresh IDE status when we receive a selection
- const status = await Ide.status()
- sync.set("ide", reconcile(status))
- })
-
- return {
- current: () => selStore.current,
- clear: () => setSelStore("current", null),
- formatted: () => {
- const sel = selStore.current
- if (!sel || !sel.text) return null
- const lines = sel.text.split("\n").length
- return `${lines} lines`
- },
- }
- })
-
// Automatically update model when agent changes
createEffect(() => {
const value = agent.current()
@@ -436,8 +387,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
model,
agent,
mcp,
- ide,
- selection,
}
return result
},
diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx
index 3898ad8e574..674f8ebe7df 100644
--- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx
@@ -11,7 +11,6 @@ import type {
QuestionRequest,
LspStatus,
McpStatus,
- IdeStatus,
FormatterStatus,
SessionStatus,
ProviderListResponse,
@@ -36,7 +35,6 @@ import { useArgs } from "./args"
import { batch, onMount } from "solid-js"
import { Log } from "@/util/log"
import type { Path } from "@opencode-ai/sdk"
-import { Ide } from "@/ide"
export const { use: useSync, provider: SyncProvider } = createSimpleContext({
name: "Sync",
@@ -76,7 +74,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
mcp: {
[key: string]: McpStatus
}
- ide: { [key: string]: IdeStatus }
mcp_resource: {
[key: string]: McpResource
}
@@ -106,7 +103,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
part: {},
lsp: [],
mcp: {},
- ide: {},
mcp_resource: {},
formatter: [],
vcs: undefined,
@@ -372,7 +368,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
sdk.client.command.list().then((x) => setStore("command", reconcile(x.data ?? []))),
sdk.client.lsp.status().then((x) => setStore("lsp", reconcile(x.data!))),
sdk.client.mcp.status().then((x) => setStore("mcp", reconcile(x.data!))),
- Ide.status().then((x) => setStore("ide", reconcile(x))),
// TODO: Re-enable after SDK regeneration (Phase 15) - sdk.client.experimental.resource.list()
(sdk.client as { experimental?: { resource: { list: () => Promise<{ data?: Record }> } } }).experimental?.resource.list().then((x) => setStore("mcp_resource", reconcile(x?.data ?? {}))),
sdk.client.formatter.status().then((x) => setStore("formatter", reconcile(x.data!))),
diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx
index 504257fad63..dc661d217a0 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx
@@ -8,7 +8,6 @@ import { useSync } from "../context/sync"
import { Toast } from "../ui/toast"
import { useArgs } from "../context/args"
import { useDirectory } from "../context/directory"
-import { useLocal } from "../context/local"
import { useRouteData } from "@tui/context/route"
import { usePromptRef } from "../context/prompt"
import { Installation } from "@/installation"
@@ -89,8 +88,6 @@ export function Home() {
}
})
const directory = useDirectory()
- const local = useLocal()
- const ide = createMemo(() => Object.values(sync.data.ide).find((x) => x.status === "connected"))
return (
<>
@@ -128,18 +125,6 @@ export function Home() {
{connectedMcpCount()} MCP
-
-
- ◆
- {ide()!.name}
-
-
-
-
- []
- {local.selection.formatted()}
-
-
/status
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/footer.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/footer.tsx
index 533ea604ff9..d10c49c833f 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/footer.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/footer.tsx
@@ -5,17 +5,14 @@ import { useDirectory } from "../../context/directory"
import { useConnected } from "../../component/dialog-model"
import { createStore } from "solid-js/store"
import { useRoute } from "../../context/route"
-import { useLocal } from "../../context/local"
export function Footer() {
const { theme } = useTheme()
const sync = useSync()
const route = useRoute()
- const local = useLocal()
const mcp = createMemo(() => Object.values(sync.data.mcp).filter((x) => x.status === "connected").length)
const mcpError = createMemo(() => Object.values(sync.data.mcp).some((x) => x.status === "failed"))
const lsp = createMemo(() => Object.keys(sync.data.lsp))
- const ide = createMemo(() => Object.values(sync.data.ide).find((x) => x.status === "connected"))
const permissions = createMemo(() => {
if (route.data.type !== "session") return []
return sync.data.permission[route.data.sessionID] ?? []
@@ -82,18 +79,6 @@ export function Footer() {
{mcp()} MCP
-
-
- ◆
- {ide()!.name}
-
-
-
-
- []
- {local.selection.formatted()}
-
-
/status
diff --git a/packages/opencode/src/ide/connection.ts b/packages/opencode/src/ide/connection.ts
deleted file mode 100644
index bcbb3ccba53..00000000000
--- a/packages/opencode/src/ide/connection.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import z from "zod/v4"
-import path from "path"
-import { Glob } from "bun"
-import { Log } from "../util/log"
-import { WebSocketClientTransport, McpError } from "../mcp/ws"
-import { Config } from "../config/config"
-
-const log = Log.create({ service: "ide" })
-
-const WS_PREFIX = "ws://127.0.0.1"
-
-const LockFile = {
- schema: z.object({
- port: z.number(),
- url: z.instanceof(URL),
- pid: z.number(),
- workspaceFolders: z.array(z.string()),
- ideName: z.string(),
- transport: z.string(),
- authToken: z.string(),
- }),
- async fromFile(file: string) {
- const port = parseInt(path.basename(file, ".lock"))
- const url = new URL(`${WS_PREFIX}:${port}`)
- const content = await Bun.file(file).text()
- let data: unknown
- try {
- data = JSON.parse(content)
- } catch (error) {
- log.warn("invalid lock file JSON", { file, error })
- return undefined
- }
- const parsed = this.schema.safeParse({ port, url, ...(data as object) })
- if (!parsed.success) {
- log.warn("invalid lock file schema", { file, error: parsed.error })
- return undefined
- }
- return parsed.data
- },
-}
-type LockFile = z.infer
-
-export async function discoverLockFiles(): Promise