zot/packages/agent/modes/shell_escape_test.go
patriceckhart cde9298410 Add !command shell escape and fix VS Code terminal repaints
- Shell escape: typing "!cmd" runs it via the bash tool's shell in the
  session cwd, honoring the /jail sandbox. Output is parked below the
  transcript as a styled terminal-log block until the next prompt or
  /clear, so it never enters the model conversation. Shares busy state
  with the agent: esc cancels it and no turn or other escape can start
  while one is in flight.
- VS Code terminal: full repaints used \x1b[2J, which xterm.js scrolls
  into scrollback and duplicates the frame. Clear in place via cursor
  home + erase-to-end under keepScrollback; Clear()/Resize() no longer
  eagerly wipe. Force a viewport-safe Invalidate on slash/file popup
  open and close transitions there.
- Restore the live tool-call overlay behavior (keep in-flight boxes
  visible until the tool_result reaches the transcript) and drop the
  forced repaint at turn start.
- Document the shell escape in the README.
2026-06-04 18:05:17 +02:00

52 lines
1.3 KiB
Go

package modes
import (
"strings"
"testing"
"github.com/patriceckhart/zot/packages/tui"
)
func TestShellEscapeCommand(t *testing.T) {
cases := []struct {
in string
wantCmd string
wantOK bool
}{
{"!ls -la", "ls -la", true},
{" !pwd", "pwd", true},
{"! go test ./... ", "go test ./...", true},
{"!", "", false},
{"! ", "", false},
{"ls -la", "", false},
{"/help", "", false},
{"hello !world", "", false},
}
for _, c := range cases {
cmd, ok := shellEscapeCommand(c.in)
if ok != c.wantOK || cmd != c.wantCmd {
t.Errorf("shellEscapeCommand(%q) = (%q,%v); want (%q,%v)",
c.in, cmd, ok, c.wantCmd, c.wantOK)
}
}
}
func TestRenderShellBlockStylesFooterDimmed(t *testing.T) {
i := &Interactive{}
i.cfg.Theme = tui.Theme{Tool: 2, Error: 1, Muted: 8}
ok := i.renderShellBlock("$ echo hi\n\nhi\n\n[exit 0] Took 0.1s", false)
if len(ok) == 0 {
t.Fatal("expected non-empty block")
}
// The success body uses the Tool color; the footer uses Muted.
body := strings.Join(ok, "\n")
if !strings.Contains(body, "echo hi") || !strings.Contains(body, "[exit 0]") {
t.Fatalf("block missing expected content: %q", body)
}
fail := i.renderShellBlock("$ false\n\n[exit 1] Took 0.0s", true)
if len(fail) == 0 {
t.Fatal("expected non-empty failure block")
}
}