Files
gnoma/internal/tool/bash/interactive.go
T
vikingowl 0b1392cf6b feat(pty): Phase 2 — interactive shell and bash interactive detection
- /shell [cmd]: launch user's $SHELL via tea.ExecProcess (PTY handoff)
  hands terminal to the shell and restores TUI on exit.
  /shell <cmd> runs that command in the shell directly.
  Detects $SHELL > $COMSPEC > /bin/sh|powershell.exe in order.

- bash tool: detect interactive commands before execution
  Prefix-interactive: sudo, ssh, passwd, vim/vi/nano, less/more,
  htop/top, mysql/psql, ftp/sftp, git push.
  Exact-interactive (REPL): python3/python/node/irb/iex/ghci/julia.
  Returns a tool result with interactive=true metadata and a hint to
  use /shell instead of hanging or erroring.

- completions: add /shell to builtin command list
- help: document /shell [cmd]
2026-05-07 15:52:56 +02:00

62 lines
1.5 KiB
Go

package bash
import "strings"
// interactiveHint is the tool result output returned when an interactive command is detected.
const interactiveHint = "Command requires interactive terminal input.\n" +
"Use /shell in the TUI to open a shell, or /shell <command> to run this command directly."
// isInteractiveCmd reports whether cmd needs an interactive terminal to function.
// Returns a non-empty reason string when the command is interactive, "" otherwise.
func isInteractiveCmd(cmd string) string {
lower := strings.ToLower(strings.TrimSpace(cmd))
// prefixInteractive: always interactive regardless of arguments.
for _, p := range prefixInteractive {
if lower == p || strings.HasPrefix(lower, p+" ") || strings.HasPrefix(lower, p+"\t") {
return p + " requires an interactive terminal"
}
}
// exactInteractive: interactive only when invoked as a bare command (REPL mode).
for _, p := range exactInteractive {
if lower == p {
return p + " opens an interactive REPL"
}
}
return ""
}
// prefixInteractive lists commands that are interactive regardless of their arguments.
var prefixInteractive = []string{
"sudo",
"ssh",
"passwd",
"vim",
"vi",
"nano",
"less",
"more",
"htop",
"top",
"mysql",
"psql",
"ftp",
"sftp",
"git push",
}
// exactInteractive lists commands that are interactive only when invoked without arguments
// (i.e., they open a REPL). With arguments they run scripts non-interactively.
var exactInteractive = []string{
"python3",
"python",
"python2",
"node",
"irb",
"iex",
"ghci",
"julia",
}