package cli import ( "encoding/json" "io" "net/http" "net/http/httptest" "reflect" "strings" "testing" ) func TestAgentListUsesCachedCatalogByDefault(t *testing.T) { cfg := setConfigEnv(t) var requests []string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { appendPrimaryRequest(&requests, r) w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodGet && r.URL.Path == "/api/v1/agents" { _, _ = io.WriteString(w, `{"supported":[{"id":"codex","label":"Codex"}],"installed":[],"authorized":[]}`) return } http.NotFound(w, r) })) t.Cleanup(srv.Close) writeRunFileFor(t, cfg, srv) out, errOut, err := executeCLI(t, Deps{ProcessAlive: func(int) bool { return true }}, "agent", "ls") if err != nil { t.Fatalf("agent ls failed: %v stderr=%s", err, errOut) } if !strings.Contains(out, "codex") || !strings.Contains(out, "needs install") { t.Fatalf("output missing table labels:\n%s", out) } want := []string{"GET /api/v1/agents"} if !reflect.DeepEqual(requests, want) { t.Fatalf("requests=%#v want %#v", requests, want) } } func TestAgentListRefreshAndStatuses(t *testing.T) { cfg := setConfigEnv(t) var requests []string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { appendPrimaryRequest(&requests, r) w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodPost && r.URL.Path == "/api/v1/agents/refresh" { _, _ = io.WriteString(w, `{"supported":[{"id":"aider","label":"Aider"},{"id":"codex","label":"Codex"},{"id":"goose","label":"Goose"},{"id":"opencode","label":"OpenCode"}],"installed":[{"id":"aider","label":"Aider","authStatus":"unauthorized"},{"id":"codex","label":"Codex","authStatus":"authorized"},{"id":"goose","label":"Goose","authStatus":"unknown"}],"authorized":[{"id":"codex","label":"Codex","authStatus":"authorized"}]}`) return } http.NotFound(w, r) })) t.Cleanup(srv.Close) writeRunFileFor(t, cfg, srv) out, errOut, err := executeCLI(t, Deps{ProcessAlive: func(int) bool { return true }}, "agent", "ls", "--refresh") if err != nil { t.Fatalf("agent ls --refresh failed: %v stderr=%s", err, errOut) } for _, want := range []string{"codex", "authorized", "aider", "needs auth", "goose", "auth unknown", "opencode", "needs install"} { if !strings.Contains(out, want) { t.Fatalf("output missing %q:\n%s", want, out) } } want := []string{"POST /api/v1/agents/refresh"} if !reflect.DeepEqual(requests, want) { t.Fatalf("requests=%#v want %#v", requests, want) } } func TestAgentListJSONEmitsRawCatalog(t *testing.T) { cfg := setConfigEnv(t) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodGet && r.URL.Path == "/api/v1/agents" { _, _ = io.WriteString(w, authorizedAgentsJSON("codex")) return } http.NotFound(w, r) })) t.Cleanup(srv.Close) writeRunFileFor(t, cfg, srv) out, errOut, err := executeCLI(t, Deps{ProcessAlive: func(int) bool { return true }}, "agent", "ls", "--json") if err != nil { t.Fatalf("agent ls --json failed: %v stderr=%s", err, errOut) } var inv agentInventory if err := json.Unmarshal([]byte(out), &inv); err != nil { t.Fatalf("json output did not decode: %v\n%s", err, out) } if len(inv.Supported) != 1 || len(inv.Installed) != 1 || len(inv.Authorized) != 1 { t.Fatalf("inventory = %#v", inv) } }