feat(tools): add interactive_bash tool for tmux session management
Add a new tool for managing tmux sessions with automatic tracking and cleanup: - interactive_bash tool: Accepts tmux commands via tmux_command parameter - Session tracking hook: Tracks omo-* prefixed tmux sessions per OpenCode session - System reminder: Appends active session list after create/delete operations - Auto cleanup: Kills all tracked tmux sessions on OpenCode session deletion - Output truncation: Registered in TRUNCATABLE_TOOLS for long capture-pane outputs 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
21
src/tools/interactive-bash/constants.ts
Normal file
21
src/tools/interactive-bash/constants.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export const DEFAULT_TIMEOUT_MS = 60_000
|
||||
|
||||
export const INTERACTIVE_BASH_DESCRIPTION = `Execute tmux commands for interactive terminal session management.
|
||||
|
||||
This tool provides access to tmux for creating and managing persistent terminal sessions.
|
||||
Use it to run interactive CLI applications, maintain long-running processes, or work with multiple terminal sessions.
|
||||
|
||||
Parameters:
|
||||
- tmux_command: The tmux command to execute (e.g., "new-session -d -s omo-dev", "send-keys -t omo-dev 'ls' Enter")
|
||||
|
||||
Examples:
|
||||
- Create session: "new-session -d -s omo-test"
|
||||
- Send keys: "send-keys -t omo-test 'npm run dev' Enter"
|
||||
- Capture output: "capture-pane -t omo-test -p"
|
||||
- List sessions: "list-sessions"
|
||||
- Kill session: "kill-session -t omo-test"
|
||||
|
||||
Notes:
|
||||
- Session names should follow the pattern "omo-{name}" for automatic tracking
|
||||
- Use -d flag with new-session to create detached sessions
|
||||
- Use capture-pane -p to retrieve terminal output`
|
||||
3
src/tools/interactive-bash/index.ts
Normal file
3
src/tools/interactive-bash/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { interactive_bash } from "./tools"
|
||||
|
||||
export { interactive_bash }
|
||||
43
src/tools/interactive-bash/tools.ts
Normal file
43
src/tools/interactive-bash/tools.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { tool } from "@opencode-ai/plugin/tool"
|
||||
import { DEFAULT_TIMEOUT_MS, INTERACTIVE_BASH_DESCRIPTION } from "./constants"
|
||||
|
||||
export const interactive_bash = tool({
|
||||
description: INTERACTIVE_BASH_DESCRIPTION,
|
||||
args: {
|
||||
tmux_command: tool.schema.string().describe("The tmux command to execute (without 'tmux' prefix)"),
|
||||
},
|
||||
execute: async (args) => {
|
||||
try {
|
||||
const parts = args.tmux_command.split(/\s+/).filter((p) => p.length > 0)
|
||||
|
||||
if (parts.length === 0) {
|
||||
return "Error: Empty tmux command"
|
||||
}
|
||||
|
||||
const proc = Bun.spawn(["tmux", ...parts], {
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
})
|
||||
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
const id = setTimeout(() => {
|
||||
proc.kill()
|
||||
reject(new Error(`Timeout after ${DEFAULT_TIMEOUT_MS}ms`))
|
||||
}, DEFAULT_TIMEOUT_MS)
|
||||
proc.exited.then(() => clearTimeout(id))
|
||||
})
|
||||
|
||||
const stdout = await Promise.race([new Response(proc.stdout).text(), timeoutPromise])
|
||||
const stderr = await new Response(proc.stderr).text()
|
||||
const exitCode = await proc.exited
|
||||
|
||||
if (exitCode !== 0 && stderr.trim()) {
|
||||
return `Error: ${stderr.trim()}`
|
||||
}
|
||||
|
||||
return stdout || "(no output)"
|
||||
} catch (e) {
|
||||
return `Error: ${e instanceof Error ? e.message : String(e)}`
|
||||
}
|
||||
},
|
||||
})
|
||||
3
src/tools/interactive-bash/types.ts
Normal file
3
src/tools/interactive-bash/types.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface InteractiveBashArgs {
|
||||
tmux_command: string
|
||||
}
|
||||
Reference in New Issue
Block a user