Merge branch 'remove-session-rename-hook'
This commit is contained in:
@@ -1,21 +0,0 @@
|
|||||||
export function detectInterrupt(error: unknown): boolean {
|
|
||||||
if (!error) return false
|
|
||||||
|
|
||||||
if (typeof error === "object") {
|
|
||||||
const errObj = error as Record<string, unknown>
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
export * from "./types"
|
|
||||||
export * from "./state"
|
export * from "./state"
|
||||||
export * from "./detector"
|
|
||||||
|
|||||||
@@ -1,31 +1,11 @@
|
|||||||
import type { SessionErrorState, SessionInterruptState } from "./types"
|
|
||||||
|
|
||||||
export const sessionErrorState = new Map<string, SessionErrorState>()
|
|
||||||
export const sessionInterruptState = new Map<string, SessionInterruptState>()
|
|
||||||
export const subagentSessions = new Set<string>()
|
export const subagentSessions = new Set<string>()
|
||||||
export const sessionFirstMessageProcessed = new Set<string>()
|
|
||||||
|
|
||||||
export let currentSessionID: string | undefined
|
|
||||||
export let currentSessionTitle: string | undefined
|
|
||||||
export let mainSessionID: 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) {
|
export function setMainSession(id: string | undefined) {
|
||||||
mainSessionID = id
|
mainSessionID = id
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentSessionID(): string | undefined {
|
|
||||||
return currentSessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCurrentSessionTitle(): string | undefined {
|
|
||||||
return currentSessionTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMainSessionID(): string | undefined {
|
export function getMainSessionID(): string | undefined {
|
||||||
return mainSessionID
|
return mainSessionID
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
export interface SessionErrorState {
|
|
||||||
hasError: boolean
|
|
||||||
errorMessage?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SessionInterruptState {
|
|
||||||
interrupted: boolean
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./title"
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
export type SessionStatus = "ready" | "processing" | "tool" | "error" | "idle"
|
|
||||||
|
|
||||||
const STATUS_ICONS: Record<SessionStatus, string> = {
|
|
||||||
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}`)
|
|
||||||
}
|
|
||||||
72
src/index.ts
72
src/index.ts
@@ -39,12 +39,9 @@ import {
|
|||||||
} from "./features/claude-code-agent-loader";
|
} from "./features/claude-code-agent-loader";
|
||||||
import { loadMcpConfigs } from "./features/claude-code-mcp-loader";
|
import { loadMcpConfigs } from "./features/claude-code-mcp-loader";
|
||||||
import {
|
import {
|
||||||
setCurrentSession,
|
|
||||||
setMainSession,
|
setMainSession,
|
||||||
getMainSessionID,
|
getMainSessionID,
|
||||||
getCurrentSessionTitle,
|
|
||||||
} from "./features/claude-code-session-state";
|
} from "./features/claude-code-session-state";
|
||||||
import { updateTerminalTitle } from "./features/terminal";
|
|
||||||
import { builtinTools, createCallOmoAgent, createBackgroundTools, createLookAt, interactive_bash, getTmuxPath } from "./tools";
|
import { builtinTools, createCallOmoAgent, createBackgroundTools, createLookAt, interactive_bash, getTmuxPath } from "./tools";
|
||||||
import { BackgroundManager } from "./features/background-agent";
|
import { BackgroundManager } from "./features/background-agent";
|
||||||
import { createBuiltinMcps } from "./mcp";
|
import { createBuiltinMcps } from "./mcp";
|
||||||
@@ -252,8 +249,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
? createEmptyMessageSanitizerHook()
|
? createEmptyMessageSanitizerHook()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
updateTerminalTitle({ sessionId: "main" });
|
|
||||||
|
|
||||||
const backgroundManager = new BackgroundManager(ctx);
|
const backgroundManager = new BackgroundManager(ctx);
|
||||||
|
|
||||||
const backgroundNotificationHook = isHookEnabled("background-notification")
|
const backgroundNotificationHook = isHookEnabled("background-notification")
|
||||||
@@ -427,28 +422,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
| undefined;
|
| undefined;
|
||||||
if (!sessionInfo?.parentID) {
|
if (!sessionInfo?.parentID) {
|
||||||
setMainSession(sessionInfo?.id);
|
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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,11 +429,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
const sessionInfo = props?.info as { id?: string } | undefined;
|
const sessionInfo = props?.info as { id?: string } | undefined;
|
||||||
if (sessionInfo?.id === getMainSessionID()) {
|
if (sessionInfo?.id === getMainSessionID()) {
|
||||||
setMainSession(undefined);
|
setMainSession(undefined);
|
||||||
setCurrentSession(undefined, undefined);
|
|
||||||
updateTerminalTitle({
|
|
||||||
sessionId: "main",
|
|
||||||
status: "idle",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,27 +456,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
.catch(() => {});
|
.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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -528,16 +475,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
...(isExploreOrLibrarian ? { call_omo_agent: false } : {}),
|
...(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) => {
|
"tool.execute.after": async (input, output) => {
|
||||||
@@ -551,15 +488,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
|
await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
|
||||||
await agentUsageReminder?.["tool.execute.after"](input, output);
|
await agentUsageReminder?.["tool.execute.after"](input, output);
|
||||||
await interactiveBashSession?.["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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user