package inbox import ( "os" "path/filepath" "testing" ) func TestShowReturnsThreadAndMessageHistory(t *testing.T) { t.Parallel() dbPath := filepath.Join(t.TempDir(), "coord.db") runInboxCommand(t, "--db", dbPath, "--json", "init") sendOut := runInboxCommand( t, "--db", dbPath, "--json", "send", "--from", "leader", "--to", "worker-a", "--subject", "Implement feature X", "--summary", "Initial request", ) var sendResp map[string]any mustDecodeJSON(t, sendOut, &sendResp) threadID := nestedString(t, sendResp, "data", "thread", "thread_id") runInboxCommand( t, "--db", dbPath, "--json", "send", "--from", "leader", "--to", "worker-a", "--thread", threadID, "--summary", "Follow-up request", "--body", "Please include request logging.", ) showOut := runInboxCommand(t, "--db", dbPath, "--json", "show", "--thread", threadID) var showResp map[string]any mustDecodeJSON(t, showOut, &showResp) if got := nestedString(t, showResp, "data", "thread", "thread_id"); got != threadID { t.Fatalf("expected thread %q, got %q", threadID, got) } messages, ok := nestedValue(t, showResp, "data", "messages").([]any) if !ok || len(messages) != 2 { t.Fatalf("expected two ordered messages, got %#v", nestedValue(t, showResp, "data", "messages")) } first, ok := messages[0].(map[string]any) if !ok { t.Fatalf("expected first message object, got %#v", messages[0]) } second, ok := messages[1].(map[string]any) if !ok { t.Fatalf("expected second message object, got %#v", messages[1]) } if got := first["summary"]; got != "Initial request" { t.Fatalf("expected first summary Initial request, got %#v", got) } if got := second["summary"]; got != "Follow-up request" { t.Fatalf("expected second summary Follow-up request, got %#v", got) } } func TestShowIncludesArtifactsPerMessage(t *testing.T) { t.Parallel() tempDir := t.TempDir() dbPath := filepath.Join(tempDir, "coord.db") artifactPath := filepath.Join(tempDir, "task.md") if err := os.WriteFile(artifactPath, []byte("task brief"), 0o644); err != nil { t.Fatalf("write artifact file: %v", err) } runInboxCommand(t, "--db", dbPath, "--json", "init") sendOut := runInboxCommand( t, "--db", dbPath, "--json", "send", "--from", "leader", "--to", "worker-a", "--subject", "Artifact task", "--summary", "Attach brief", "--artifact", artifactPath, "--artifact-kind", "brief", "--artifact-metadata-json", `{"label":"task-brief"}`, ) var sendResp map[string]any mustDecodeJSON(t, sendOut, &sendResp) threadID := nestedString(t, sendResp, "data", "thread", "thread_id") showOut := runInboxCommand(t, "--db", dbPath, "--json", "show", "--thread", threadID) var showResp map[string]any mustDecodeJSON(t, showOut, &showResp) messages, ok := nestedValue(t, showResp, "data", "messages").([]any) if !ok || len(messages) == 0 { t.Fatalf("expected messages with artifacts, got %#v", nestedValue(t, showResp, "data", "messages")) } first, ok := messages[0].(map[string]any) if !ok { t.Fatalf("expected message object, got %#v", messages[0]) } artifacts, ok := first["artifacts"].([]any) if !ok || len(artifacts) != 1 { t.Fatalf("expected one artifact, got %#v", first["artifacts"]) } artifact, ok := artifacts[0].(map[string]any) if !ok { t.Fatalf("expected artifact object, got %#v", artifacts[0]) } if got := artifact["path"]; got != artifactPath { t.Fatalf("expected artifact path %q, got %#v", artifactPath, got) } if got := artifact["kind"]; got != "brief" { t.Fatalf("expected artifact kind brief, got %#v", got) } } func TestShowMarkReadAdvancesReadCursor(t *testing.T) { t.Parallel() dbPath := filepath.Join(t.TempDir(), "coord.db") runInboxCommand(t, "--db", dbPath, "--json", "init") sendOut := runInboxCommand( t, "--db", dbPath, "--json", "send", "--from", "leader", "--to", "worker-e", "--subject", "Review nav copy", "--summary", "Check wording", ) var sendResp map[string]any mustDecodeJSON(t, sendOut, &sendResp) threadID := nestedString(t, sendResp, "data", "thread", "thread_id") runInboxCommand( t, "--db", dbPath, "--json", "fetch", "--agent", "worker-e", "--status", "pending", "--unread", ) runInboxCommand( t, "--db", dbPath, "--agent", "worker-e", "--json", "show", "--thread", threadID, "--mark-read", ) stdout, _, exitCode := executeInboxCommand( "--db", dbPath, "--json", "fetch", "--agent", "worker-e", "--status", "pending", "--unread", ) if exitCode != 10 { t.Fatalf("expected unread fetch to be empty after mark-read, got exit=%d with %s", exitCode, stdout) } assertErrorJSON(t, stdout, "no_matching_work") } func TestShowRejectsWhenThreadMissing(t *testing.T) { t.Parallel() dbPath := filepath.Join(t.TempDir(), "coord.db") runInboxCommand(t, "--db", dbPath, "--json", "init") stdout, _, exitCode := executeInboxCommand( "--db", dbPath, "--json", "show", "--thread", "thr_missing", ) if exitCode != 40 { t.Fatalf("expected not-found exit code 40, got %d with %s", exitCode, stdout) } assertErrorJSON(t, stdout, "not_found") }