Add tmux availability check for conditional interactive_bash tool registration
- Implement getTmuxPath() utility to detect tmux availability at plugin load time - Add getCachedTmuxPath() for retrieving cached tmux path - Add startBackgroundCheck() for asynchronous tmux detection - Conditionally register interactive_bash tool only when tmux is available - Silently skip registration without error messages if tmux not found - Export utilities from tools/interactive-bash/index.ts Tool now gracefully handles systems without tmux installed. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -44,7 +44,7 @@ import {
|
|||||||
getCurrentSessionTitle,
|
getCurrentSessionTitle,
|
||||||
} from "./features/claude-code-session-state";
|
} from "./features/claude-code-session-state";
|
||||||
import { updateTerminalTitle } from "./features/terminal";
|
import { updateTerminalTitle } from "./features/terminal";
|
||||||
import { builtinTools, createCallOmoAgent, createBackgroundTools, createLookAt } 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";
|
||||||
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig, type HookName } from "./config";
|
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig, type HookName } from "./config";
|
||||||
@@ -263,6 +263,8 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
? await createGoogleAntigravityAuthPlugin(ctx)
|
? await createGoogleAntigravityAuthPlugin(ctx)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const tmuxAvailable = await getTmuxPath();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(googleAuthHooks ? { auth: googleAuthHooks.auth } : {}),
|
...(googleAuthHooks ? { auth: googleAuthHooks.auth } : {}),
|
||||||
|
|
||||||
@@ -271,6 +273,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
...backgroundTools,
|
...backgroundTools,
|
||||||
call_omo_agent: callOmoAgent,
|
call_omo_agent: callOmoAgent,
|
||||||
look_at: lookAt,
|
look_at: lookAt,
|
||||||
|
...(tmuxAvailable ? { interactive_bash } : {}),
|
||||||
},
|
},
|
||||||
|
|
||||||
"chat.message": async (input, output) => {
|
"chat.message": async (input, output) => {
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ import { grep } from "./grep"
|
|||||||
import { glob } from "./glob"
|
import { glob } from "./glob"
|
||||||
import { slashcommand } from "./slashcommand"
|
import { slashcommand } from "./slashcommand"
|
||||||
import { skill } from "./skill"
|
import { skill } from "./skill"
|
||||||
import { interactive_bash } from "./interactive-bash"
|
|
||||||
|
export { interactive_bash, startBackgroundCheck as startTmuxCheck } from "./interactive-bash"
|
||||||
|
export { getTmuxPath } from "./interactive-bash/utils"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createBackgroundTask,
|
createBackgroundTask,
|
||||||
@@ -63,5 +65,4 @@ export const builtinTools = {
|
|||||||
glob,
|
glob,
|
||||||
slashcommand,
|
slashcommand,
|
||||||
skill,
|
skill,
|
||||||
interactive_bash,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import { interactive_bash } from "./tools"
|
import { interactive_bash } from "./tools"
|
||||||
|
import { startBackgroundCheck } from "./utils"
|
||||||
|
|
||||||
export { interactive_bash }
|
export { interactive_bash, startBackgroundCheck }
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { tool } from "@opencode-ai/plugin/tool"
|
import { tool } from "@opencode-ai/plugin/tool"
|
||||||
import { DEFAULT_TIMEOUT_MS, INTERACTIVE_BASH_DESCRIPTION } from "./constants"
|
import { DEFAULT_TIMEOUT_MS, INTERACTIVE_BASH_DESCRIPTION } from "./constants"
|
||||||
|
import { getCachedTmuxPath } from "./utils"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quote-aware command tokenizer with escape handling
|
* Quote-aware command tokenizer with escape handling
|
||||||
@@ -53,13 +54,15 @@ export const interactive_bash = tool({
|
|||||||
},
|
},
|
||||||
execute: async (args) => {
|
execute: async (args) => {
|
||||||
try {
|
try {
|
||||||
|
const tmuxPath = getCachedTmuxPath() ?? "tmux"
|
||||||
|
|
||||||
const parts = tokenizeCommand(args.tmux_command)
|
const parts = tokenizeCommand(args.tmux_command)
|
||||||
|
|
||||||
if (parts.length === 0) {
|
if (parts.length === 0) {
|
||||||
return "Error: Empty tmux command"
|
return "Error: Empty tmux command"
|
||||||
}
|
}
|
||||||
|
|
||||||
const proc = Bun.spawn(["tmux", ...parts], {
|
const proc = Bun.spawn([tmuxPath, ...parts], {
|
||||||
stdout: "pipe",
|
stdout: "pipe",
|
||||||
stderr: "pipe",
|
stderr: "pipe",
|
||||||
})
|
})
|
||||||
|
|||||||
71
src/tools/interactive-bash/utils.ts
Normal file
71
src/tools/interactive-bash/utils.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { spawn } from "bun"
|
||||||
|
|
||||||
|
let tmuxPath: string | null = null
|
||||||
|
let initPromise: Promise<string | null> | null = null
|
||||||
|
|
||||||
|
async function findTmuxPath(): Promise<string | null> {
|
||||||
|
const isWindows = process.platform === "win32"
|
||||||
|
const cmd = isWindows ? "where" : "which"
|
||||||
|
|
||||||
|
try {
|
||||||
|
const proc = spawn([cmd, "tmux"], {
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
})
|
||||||
|
|
||||||
|
const exitCode = await proc.exited
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdout = await new Response(proc.stdout).text()
|
||||||
|
const path = stdout.trim().split("\n")[0]
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyProc = spawn([path, "-V"], {
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
})
|
||||||
|
|
||||||
|
const verifyExitCode = await verifyProc.exited
|
||||||
|
if (verifyExitCode !== 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTmuxPath(): Promise<string | null> {
|
||||||
|
if (tmuxPath !== null) {
|
||||||
|
return tmuxPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initPromise) {
|
||||||
|
return initPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
initPromise = (async () => {
|
||||||
|
const path = await findTmuxPath()
|
||||||
|
tmuxPath = path
|
||||||
|
return path
|
||||||
|
})()
|
||||||
|
|
||||||
|
return initPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCachedTmuxPath(): string | null {
|
||||||
|
return tmuxPath
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startBackgroundCheck(): void {
|
||||||
|
if (!initPromise) {
|
||||||
|
initPromise = getTmuxPath()
|
||||||
|
initPromise.catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user