From 8cdbd1cbc0bb2357fd3700eb4fa2b04e0d0bef4a Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Wed, 17 Dec 2025 16:12:08 +0900 Subject: [PATCH] refactor: remove terminal title update feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenCode now supports terminal title updates natively (since v1.0.150, commit 8346550), making this plugin feature redundant. Remove the entire terminal title feature and clean up associated dead code. Ref: https://github.com/sst/opencode/commit/8346550 Removed: - src/features/terminal/ (title.ts, index.ts) - src/features/claude-code-session-state/detector.ts (dead code) - src/features/claude-code-session-state/types.ts (dead code) - Session title tracking (setCurrentSession, getCurrentSessionTitle) - Terminal title update calls from event handlers Retained: - subagentSessions (used by background-agent, session-notification) - mainSessionID tracking (used by session recovery) 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- .../claude-code-session-state/detector.ts | 21 ------ .../claude-code-session-state/index.ts | 2 - .../claude-code-session-state/state.ts | 20 ------ .../claude-code-session-state/types.ts | 8 --- src/features/terminal/index.ts | 1 - src/features/terminal/title.ts | 62 ---------------- src/index.ts | 72 ------------------- 7 files changed, 186 deletions(-) delete mode 100644 src/features/claude-code-session-state/detector.ts delete mode 100644 src/features/claude-code-session-state/types.ts delete mode 100644 src/features/terminal/index.ts delete mode 100644 src/features/terminal/title.ts diff --git a/src/features/claude-code-session-state/detector.ts b/src/features/claude-code-session-state/detector.ts deleted file mode 100644 index 9cb8178..0000000 --- a/src/features/claude-code-session-state/detector.ts +++ /dev/null @@ -1,21 +0,0 @@ -export function detectInterrupt(error: unknown): boolean { - if (!error) return false - - if (typeof error === "object") { - const errObj = error as Record - const name = errObj.name as string | undefined - const message = errObj.message as string | undefined - - if (name === "MessageAbortedError" || name === "AbortError") return true - if (name === "DOMException" && message?.includes("abort")) return true - const msgLower = message?.toLowerCase() - if (msgLower?.includes("aborted") || msgLower?.includes("cancelled") || msgLower?.includes("interrupted")) return true - } - - if (typeof error === "string") { - const lower = error.toLowerCase() - return lower.includes("abort") || lower.includes("cancel") || lower.includes("interrupt") - } - - return false -} diff --git a/src/features/claude-code-session-state/index.ts b/src/features/claude-code-session-state/index.ts index 665b542..2b19e02 100644 --- a/src/features/claude-code-session-state/index.ts +++ b/src/features/claude-code-session-state/index.ts @@ -1,3 +1 @@ -export * from "./types" export * from "./state" -export * from "./detector" diff --git a/src/features/claude-code-session-state/state.ts b/src/features/claude-code-session-state/state.ts index d0a57b9..751ab83 100644 --- a/src/features/claude-code-session-state/state.ts +++ b/src/features/claude-code-session-state/state.ts @@ -1,31 +1,11 @@ -import type { SessionErrorState, SessionInterruptState } from "./types" - -export const sessionErrorState = new Map() -export const sessionInterruptState = new Map() export const subagentSessions = new Set() -export const sessionFirstMessageProcessed = new Set() -export let currentSessionID: string | undefined -export let currentSessionTitle: string | undefined export let mainSessionID: string | undefined -export function setCurrentSession(id: string | undefined, title: string | undefined) { - currentSessionID = id - currentSessionTitle = title -} - export function setMainSession(id: string | undefined) { mainSessionID = id } -export function getCurrentSessionID(): string | undefined { - return currentSessionID -} - -export function getCurrentSessionTitle(): string | undefined { - return currentSessionTitle -} - export function getMainSessionID(): string | undefined { return mainSessionID } diff --git a/src/features/claude-code-session-state/types.ts b/src/features/claude-code-session-state/types.ts deleted file mode 100644 index 4939871..0000000 --- a/src/features/claude-code-session-state/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface SessionErrorState { - hasError: boolean - errorMessage?: string -} - -export interface SessionInterruptState { - interrupted: boolean -} diff --git a/src/features/terminal/index.ts b/src/features/terminal/index.ts deleted file mode 100644 index 4546fd1..0000000 --- a/src/features/terminal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./title" diff --git a/src/features/terminal/title.ts b/src/features/terminal/title.ts deleted file mode 100644 index 58a81dd..0000000 --- a/src/features/terminal/title.ts +++ /dev/null @@ -1,62 +0,0 @@ -export type SessionStatus = "ready" | "processing" | "tool" | "error" | "idle" - -const STATUS_ICONS: Record = { - ready: "", - processing: "◐", - tool: "⚡", - error: "✖", - idle: "○", -} - -export interface TitleContext { - sessionId: string - sessionTitle?: string - directory?: string - status?: SessionStatus - currentTool?: string - customSuffix?: string -} - -const DEFAULT_TITLE = "OpenCode" -const MAX_TITLE_LENGTH = 30 - -function truncate(str: string, maxLen: number): string { - if (str.length <= maxLen) return str - return str.slice(0, maxLen - 1) + "…" -} - -export function formatTerminalTitle(ctx: TitleContext): string { - const title = ctx.sessionTitle || DEFAULT_TITLE - const truncatedTitle = truncate(title, MAX_TITLE_LENGTH) - - const parts: string[] = ["[OpenCode]", truncatedTitle] - - if (ctx.status) { - parts.push(STATUS_ICONS[ctx.status]) - } - - return parts.join(" ") -} - -function isTmuxEnvironment(): boolean { - return !!process.env.TMUX || process.env.TERM_PROGRAM === "tmux" -} - -export function setTerminalTitle(title: string): void { - // Use stderr to avoid race conditions with stdout buffer - // ANSI escape sequences work on stderr as well - process.stderr.write(`\x1b]0;${title}\x07`) - - if (isTmuxEnvironment()) { - process.stderr.write(`\x1bk${title}\x1b\\`) - } -} - -export function updateTerminalTitle(ctx: TitleContext): void { - const title = formatTerminalTitle(ctx) - setTerminalTitle(title) -} - -export function resetTerminalTitle(): void { - setTerminalTitle(`[OpenCode] ${DEFAULT_TITLE}`) -} diff --git a/src/index.ts b/src/index.ts index 07a7a6c..73dbfca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,12 +39,9 @@ import { } from "./features/claude-code-agent-loader"; import { loadMcpConfigs } from "./features/claude-code-mcp-loader"; import { - setCurrentSession, setMainSession, getMainSessionID, - getCurrentSessionTitle, } from "./features/claude-code-session-state"; -import { updateTerminalTitle } from "./features/terminal"; import { builtinTools, createCallOmoAgent, createBackgroundTools, createLookAt, interactive_bash, getTmuxPath } from "./tools"; import { BackgroundManager } from "./features/background-agent"; import { createBuiltinMcps } from "./mcp"; @@ -252,8 +249,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { ? createEmptyMessageSanitizerHook() : null; - updateTerminalTitle({ sessionId: "main" }); - const backgroundManager = new BackgroundManager(ctx); const backgroundNotificationHook = isHookEnabled("background-notification") @@ -421,28 +416,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { | undefined; if (!sessionInfo?.parentID) { setMainSession(sessionInfo?.id); - setCurrentSession(sessionInfo?.id, sessionInfo?.title); - updateTerminalTitle({ - sessionId: sessionInfo?.id || "main", - status: "idle", - directory: ctx.directory, - sessionTitle: sessionInfo?.title, - }); - } - } - - if (event.type === "session.updated") { - const sessionInfo = props?.info as - | { id?: string; title?: string; parentID?: string } - | undefined; - if (!sessionInfo?.parentID) { - setCurrentSession(sessionInfo?.id, sessionInfo?.title); - updateTerminalTitle({ - sessionId: sessionInfo?.id || "main", - status: "processing", - directory: ctx.directory, - sessionTitle: sessionInfo?.title, - }); } } @@ -450,11 +423,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { const sessionInfo = props?.info as { id?: string } | undefined; if (sessionInfo?.id === getMainSessionID()) { setMainSession(undefined); - setCurrentSession(undefined, undefined); - updateTerminalTitle({ - sessionId: "main", - status: "idle", - }); } } @@ -482,27 +450,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { .catch(() => {}); } } - - if (sessionID && sessionID === getMainSessionID()) { - updateTerminalTitle({ - sessionId: sessionID, - status: "error", - directory: ctx.directory, - sessionTitle: getCurrentSessionTitle(), - }); - } - } - - if (event.type === "session.idle") { - const sessionID = props?.sessionID as string | undefined; - if (sessionID && sessionID === getMainSessionID()) { - updateTerminalTitle({ - sessionId: sessionID, - status: "idle", - directory: ctx.directory, - sessionTitle: getCurrentSessionTitle(), - }); - } } }, @@ -522,16 +469,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { ...(isExploreOrLibrarian ? { call_omo_agent: false } : {}), }; } - - if (input.sessionID === getMainSessionID()) { - updateTerminalTitle({ - sessionId: input.sessionID, - status: "tool", - currentTool: input.tool, - directory: ctx.directory, - sessionTitle: getCurrentSessionTitle(), - }); - } }, "tool.execute.after": async (input, output) => { @@ -545,15 +482,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { await emptyTaskResponseDetector?.["tool.execute.after"](input, output); await agentUsageReminder?.["tool.execute.after"](input, output); await interactiveBashSession?.["tool.execute.after"](input, output); - - if (input.sessionID === getMainSessionID()) { - updateTerminalTitle({ - sessionId: input.sessionID, - status: "idle", - directory: ctx.directory, - sessionTitle: getCurrentSessionTitle(), - }); - } }, }; };