Files
gnoma/internal/tool/bash/interactive_test.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

83 lines
1.9 KiB
Go

package bash
import "testing"
func TestIsInteractiveCmd(t *testing.T) {
tests := []struct {
cmd string
wantHit bool
}{
// prefix-interactive: always interactive with any args
{"sudo apt install foo", true},
{"sudo", true},
{"sudo\tls", true},
{"ssh user@host", true},
{"ssh -p 2222 host", true},
{"ssh", true},
{"passwd", true},
{"passwd root", true},
{"vim file.txt", true},
{"vim", true},
{"vi /etc/hosts", true},
{"vi", true},
{"nano config.yml", true},
{"nano", true},
{"less output.log", true},
{"more pager.txt", true},
{"htop", true},
{"top", true},
{"top -b", true},
{"mysql -u root", true},
{"psql -U postgres", true},
{"ftp example.com", true},
{"sftp user@host", true},
{"git push origin main", true},
{"git push", true},
// exact-interactive: interactive only as bare command (REPL)
{"python3", true},
{"python", true},
{"python2", true},
{"node", true},
{"irb", true},
{"iex", true},
{"ghci", true},
{"julia", true},
// exact-interactive: args → NOT interactive (running a script)
{"python3 script.py", false},
{"python3 -c 'print(1)'", false},
{"python2 run.py", false},
{"node server.js", false},
{"irb file.rb", false},
{"julia script.jl", false},
// non-interactive commands
{"ls -la", false},
{"grep foo bar.txt", false},
{"cat /etc/hosts", false},
{"git status", false},
{"git pull", false},
{"git diff", false},
{"echo hello", false},
{"pwd", false},
{"find . -name '*.go'", false},
// should not match on prefix-sharing names
{"topological_sort", false},
{"sshkeys", false},
{"vitals", false},
{"moral", false},
{"git pushover", false},
}
for _, tt := range tests {
reason := isInteractiveCmd(tt.cmd)
got := reason != ""
if got != tt.wantHit {
t.Errorf("isInteractiveCmd(%q) hit=%v (reason=%q), want hit=%v",
tt.cmd, got, reason, tt.wantHit)
}
}
}