refactor(hooks): rename interactive-bash-blocker to non-interactive-env
- Replace regex-based command blocking with environment configuration - Add cross-platform null device support (NUL for Windows, /dev/null for Unix) - Wrap all bash commands with non-interactive environment variables - Only block TUI programs that require full PTY - Update schema, README docs, and all imports/exports 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
57
src/hooks/non-interactive-env/constants.ts
Normal file
57
src/hooks/non-interactive-env/constants.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export const HOOK_NAME = "non-interactive-env"
|
||||
|
||||
export const NULL_DEVICE = process.platform === "win32" ? "NUL" : "/dev/null"
|
||||
|
||||
export const NON_INTERACTIVE_ENV: Record<string, string> = {
|
||||
CI: "true",
|
||||
DEBIAN_FRONTEND: "noninteractive",
|
||||
GIT_TERMINAL_PROMPT: "0",
|
||||
GCM_INTERACTIVE: "never",
|
||||
HOMEBREW_NO_AUTO_UPDATE: "1",
|
||||
}
|
||||
|
||||
export const TUI_PATTERNS = [
|
||||
/\b(?:vim?|nvim|nano|emacs|pico|joe|micro|helix|hx)\b/,
|
||||
/^\s*(?:python|python3|ipython|node|bun|deno|irb|pry|ghci|erl|iex|lua|R)\s*$/,
|
||||
/\btop\b(?!\s+\|)/,
|
||||
/\bhtop\b/,
|
||||
/\bbtop\b/,
|
||||
/\bless\b(?!\s+\|)/,
|
||||
/\bmore\b(?!\s+\|)/,
|
||||
/\bman\b/,
|
||||
/\bwatch\b/,
|
||||
/\bncurses\b/,
|
||||
/\bdialog\b/,
|
||||
/\bwhiptail\b/,
|
||||
/\bmc\b/,
|
||||
/\branger\b/,
|
||||
/\bnnn\b/,
|
||||
/\blf\b/,
|
||||
/\bvifm\b/,
|
||||
/\bgitui\b/,
|
||||
/\blazygit\b/,
|
||||
/\blazydocker\b/,
|
||||
/\bk9s\b/,
|
||||
/\bselect\b.*\bin\b/,
|
||||
]
|
||||
|
||||
export const TUI_SUGGESTION = `
|
||||
[non-interactive-env]
|
||||
This command requires a full interactive terminal (TUI) which cannot be emulated.
|
||||
|
||||
**Recommendation**: Use tmux for TUI commands.
|
||||
|
||||
Example with interactive-terminal skill:
|
||||
\`\`\`
|
||||
# Start a tmux session
|
||||
tmux new-session -d -s interactive
|
||||
|
||||
# Send your command
|
||||
tmux send-keys -t interactive 'your-command-here' Enter
|
||||
|
||||
# Capture output
|
||||
tmux capture-pane -t interactive -p
|
||||
\`\`\`
|
||||
|
||||
Or use the 'interactive-terminal' skill for easier workflow.
|
||||
`
|
||||
40
src/hooks/non-interactive-env/index.ts
Normal file
40
src/hooks/non-interactive-env/index.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { HOOK_NAME, NULL_DEVICE, NON_INTERACTIVE_ENV } from "./constants"
|
||||
import { log } from "../../shared"
|
||||
|
||||
export * from "./constants"
|
||||
export * from "./types"
|
||||
|
||||
function wrapWithNonInteractiveEnv(command: string): string {
|
||||
const envPrefix = Object.entries(NON_INTERACTIVE_ENV)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join(" ")
|
||||
|
||||
return `${envPrefix} ${command} < ${NULL_DEVICE} 2>&1 || ${envPrefix} ${command} 2>&1`
|
||||
}
|
||||
|
||||
export function createNonInteractiveEnvHook(_ctx: PluginInput) {
|
||||
return {
|
||||
"tool.execute.before": async (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: Record<string, unknown> }
|
||||
): Promise<void> => {
|
||||
if (input.tool.toLowerCase() !== "bash") {
|
||||
return
|
||||
}
|
||||
|
||||
const command = output.args.command as string | undefined
|
||||
if (!command) {
|
||||
return
|
||||
}
|
||||
|
||||
output.args.command = wrapWithNonInteractiveEnv(command)
|
||||
|
||||
log(`[${HOOK_NAME}] Wrapped command with non-interactive environment`, {
|
||||
sessionID: input.sessionID,
|
||||
original: command,
|
||||
wrapped: output.args.command,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
10
src/hooks/non-interactive-env/types.ts
Normal file
10
src/hooks/non-interactive-env/types.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface NonInteractiveEnvConfig {
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export interface TUICheckResult {
|
||||
isTUI: boolean
|
||||
reason?: string
|
||||
command?: string
|
||||
matchedPattern?: string
|
||||
}
|
||||
Reference in New Issue
Block a user