Something went wrong. Try again.
small gleam coding and persistent agent daemon with a detachable cli and a canvas ui forked from okami.mom/albedo
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138package tui
import ( "errors" "strings" "testing"
tea "charm.land/bubbletea/v2"
"albedo/cli/internal/daemon" "github.com/charmbracelet/x/ansi")
func TestParseShellInputIsLiteralHumanPrefix(t *testing.T) { for _, tc := range []struct { input, command string ok bool }{ {"!echo \"foobar\"", "echo \"foobar\"", true}, {"! pwd ", "pwd", true}, {"echo !pwd", "", false}, {"/run", "", false}, {"/run is broken", "", false}, } { got, ok := parseShellInput(tc.input) if got != tc.command || ok != tc.ok { t.Errorf("parseShellInput(%q) = %q,%v; want %q,%v", tc.input, got, ok, tc.command, tc.ok) } }}
func TestFailedShellSubmissionRestoresDraftAndStableID(t *testing.T) { conn := daemon.NewConnection(daemon.ConnectionSnapshot{Port: 1}, nil) session := &daemon.Session{ID: "session", Workspace: "/work"} m := NewChatModel(session, daemon.NewChatClient(conn, session.ID)) m.shellIDsByCommand = map[string]string{"echo hi": "01a0fcea-2b00-7000-8000-000000000001"} m.shellSubmitting = true m.TextArea.Reset() m, _ = m.Update(ChatShellSubmitMsg{Err: errTestShell, SessionID: session.ID, Generation: m.Generation, OriginalInput: "!echo hi"}) if m.TextArea.Value() != "!echo hi" { t.Fatalf("draft = %q", m.TextArea.Value()) } if m.shellIDsByCommand["echo hi"] == "" { t.Fatal("uncertain retry ID was discarded") }}
func TestShellEventDeduplicatesByCommandIDAndSanitizesOutput(t *testing.T) { conn := daemon.NewConnection(daemon.ConnectionSnapshot{Port: 1}, nil) session := &daemon.Session{ID: "session", Workspace: "/work"} m := NewChatModel(session, daemon.NewChatClient(conn, session.ID)) first := daemon.ShellCommand{ID: "shell-id", Command: "echo hi", Status: "running"} m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventShellCommand, ShellCommand: &first}) second := first second.Status, second.Output = "completed", "safe\x1b]52;c;clipboard\a\n" second.OutputBytes = int64(len(second.Output)) code := int64(0) second.ExitCode = &code m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventShellCommand, ShellCommand: &second}) if m.History.Len() != 1 { t.Fatalf("history has %d shell rows", m.History.Len()) } entry := m.History.Entries()[0] rows := strings.Join(m.Renderer.shellCard(entry, 80), "\n") if strings.Contains(rows, "\x1b]52") || strings.Contains(ansi.Strip(rows), "clipboard") { t.Fatalf("terminal control text survived rendering: %q", rows) }}
// TestShellDeliveryReducerPreservesAckAndExecutionState catches out-of-order// event/history/PUT snapshots that an E2E backend test cannot deterministically// force through the terminal client's event reducer.func TestShellDeliveryReducerPreservesAckAndExecutionState(t *testing.T) { m := newTestChatModel(t, &daemon.Session{ID: "session", Workspace: "/work"}) pending := daemon.ShellCommand{ID: "shell-id", Command: "echo hi", Status: "completed", Delivery: "pending"} m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventShellCommand, ShellCommand: &pending}) m.upsertShellCommand(daemon.ShellCommand{ID: pending.ID, Command: pending.Command, Status: "completed", Delivery: "delivered"}) m.Follow = false m.SetSize(100, 24) if !strings.Contains(ansi.Strip(m.View()), "sent to agent") { t.Fatalf("ACK not visible in canonical chat view: %q", ansi.Strip(m.View())) } index := m.History.Find(pending.ID) entry := m.History.Entries()[index] rows := strings.Join(m.Renderer.shellCard(entry, 80), "\n") if !strings.Contains(ansi.Strip(rows), "sent to agent") { t.Fatalf("ACK not visible in shell card: %q", ansi.Strip(rows)) } // An older history/PUT snapshot cannot undo an ACK or resurrect execution. m.upsertShellCommand(daemon.ShellCommand{ID: pending.ID, Command: pending.Command, Status: "running", Delivery: "pending", Output: "stale"}) entry = m.History.Entries()[m.History.Find(pending.ID)] if entry.ShellCommand.Status != "completed" || entry.ShellCommand.Delivery != "delivered" { t.Fatalf("stale snapshot regressed shell state: %#v", entry.ShellCommand) } if strings.Contains(ansi.Strip(strings.Join(m.Renderer.shellCard(entry, 80), "\n")), "running · click to cancel") { t.Fatal("stale snapshot restored running/cancel state") }
m.handleStreamEvent(daemon.StreamEvent{Type: daemon.EventReset, Reason: "reconnect", ShellCommands: []daemon.ShellCommand{{ID: pending.ID, Command: pending.Command, Status: "completed", Delivery: "delivered"}}}) entry = m.History.Entries()[m.History.Find(pending.ID)] if entry.ShellCommand.Delivery != "delivered" { t.Fatalf("reset lost delivery receipt: %#v", entry.ShellCommand) }}
var errTestShell = errors.New("shell rejected")
func TestGrowingExpandedShellOutputIsRefreshed(t *testing.T) { conn := daemon.NewConnection(daemon.ConnectionSnapshot{Port: 1}, nil) session := &daemon.Session{ID: "session", Workspace: "/work"} m := NewChatModel(session, daemon.NewChatClient(conn, session.ID)) first := daemon.ShellCommand{ID: "shell-growing", Command: "yes", Status: "running", Output: "a", OutputBytes: 1} m.upsertShellCommand(first) entry := m.History.Entries()[0] entry.ShellOutputLoaded, entry.ShellExpandedOutput = true, "a" m.History.Replace(entry) first.Output, first.OutputBytes = "ab", 2 m.upsertShellCommand(first) entry = m.History.Entries()[0] if entry.ShellOutputLoaded || entry.ShellExpandedOutput != "" { t.Fatalf("stale expansion retained: %#v", entry) }}
func TestHumanComposerRoutesBangWithoutCreatingModelTurn(t *testing.T) { conn := daemon.NewConnection(daemon.ConnectionSnapshot{Port: 1}, nil) session := &daemon.Session{ID: "session", Workspace: "/work"} m := NewChatModel(session, daemon.NewChatClient(conn, session.ID)) var commands []tea.Cmd m.submitInput(`!echo "foobar"`, &commands) if !m.shellSubmitting || len(commands) != 1 || len(m.pendingUsers) != 0 { t.Fatalf("shell route state submitting=%v commands=%d model-turns=%d", m.shellSubmitting, len(commands), len(m.pendingUsers)) } if command, ok := parseShellInput(`/run is broken`); ok || command != "" { t.Fatalf("slash prose became shell command: %q", command) }}