[ORCH-132] Connect agent dashboard to real API #330
@@ -13,6 +13,8 @@ describe("AgentsController", () => {
|
|||||||
};
|
};
|
||||||
let spawnerService: {
|
let spawnerService: {
|
||||||
spawnAgent: ReturnType<typeof vi.fn>;
|
spawnAgent: ReturnType<typeof vi.fn>;
|
||||||
|
listAgentSessions: ReturnType<typeof vi.fn>;
|
||||||
|
getAgentSession: ReturnType<typeof vi.fn>;
|
||||||
};
|
};
|
||||||
let lifecycleService: {
|
let lifecycleService: {
|
||||||
getAgentLifecycleState: ReturnType<typeof vi.fn>;
|
getAgentLifecycleState: ReturnType<typeof vi.fn>;
|
||||||
@@ -30,6 +32,8 @@ describe("AgentsController", () => {
|
|||||||
|
|
||||||
spawnerService = {
|
spawnerService = {
|
||||||
spawnAgent: vi.fn(),
|
spawnAgent: vi.fn(),
|
||||||
|
listAgentSessions: vi.fn(),
|
||||||
|
getAgentSession: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
lifecycleService = {
|
lifecycleService = {
|
||||||
@@ -58,6 +62,109 @@ describe("AgentsController", () => {
|
|||||||
expect(controller).toBeDefined();
|
expect(controller).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("listAgents", () => {
|
||||||
|
it("should return empty array when no agents exist", () => {
|
||||||
|
// Arrange
|
||||||
|
spawnerService.listAgentSessions.mockReturnValue([]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = controller.listAgents();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(spawnerService.listAgentSessions).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return all agent sessions with mapped status", () => {
|
||||||
|
// Arrange
|
||||||
|
const sessions = [
|
||||||
|
{
|
||||||
|
agentId: "agent-1",
|
||||||
|
taskId: "task-1",
|
||||||
|
agentType: "worker" as const,
|
||||||
|
state: "running" as const,
|
||||||
|
context: {
|
||||||
|
repository: "repo",
|
||||||
|
branch: "main",
|
||||||
|
workItems: [],
|
||||||
|
},
|
||||||
|
spawnedAt: new Date("2026-02-05T12:00:00Z"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agentId: "agent-2",
|
||||||
|
taskId: "task-2",
|
||||||
|
agentType: "reviewer" as const,
|
||||||
|
state: "completed" as const,
|
||||||
|
context: {
|
||||||
|
repository: "repo",
|
||||||
|
branch: "main",
|
||||||
|
workItems: [],
|
||||||
|
},
|
||||||
|
spawnedAt: new Date("2026-02-05T11:00:00Z"),
|
||||||
|
completedAt: new Date("2026-02-05T11:30:00Z"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agentId: "agent-3",
|
||||||
|
taskId: "task-3",
|
||||||
|
agentType: "tester" as const,
|
||||||
|
state: "failed" as const,
|
||||||
|
context: {
|
||||||
|
repository: "repo",
|
||||||
|
branch: "main",
|
||||||
|
workItems: [],
|
||||||
|
},
|
||||||
|
spawnedAt: new Date("2026-02-05T10:00:00Z"),
|
||||||
|
error: "Test execution failed",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
spawnerService.listAgentSessions.mockReturnValue(sessions);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = controller.listAgents();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(spawnerService.listAgentSessions).toHaveBeenCalled();
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
|
expect(result[0]).toEqual({
|
||||||
|
agentId: "agent-1",
|
||||||
|
taskId: "task-1",
|
||||||
|
status: "running",
|
||||||
|
agentType: "worker",
|
||||||
|
spawnedAt: "2026-02-05T12:00:00.000Z",
|
||||||
|
completedAt: undefined,
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
expect(result[1]).toEqual({
|
||||||
|
agentId: "agent-2",
|
||||||
|
taskId: "task-2",
|
||||||
|
status: "completed",
|
||||||
|
agentType: "reviewer",
|
||||||
|
spawnedAt: "2026-02-05T11:00:00.000Z",
|
||||||
|
completedAt: "2026-02-05T11:30:00.000Z",
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
expect(result[2]).toEqual({
|
||||||
|
agentId: "agent-3",
|
||||||
|
taskId: "task-3",
|
||||||
|
status: "failed",
|
||||||
|
agentType: "tester",
|
||||||
|
spawnedAt: "2026-02-05T10:00:00.000Z",
|
||||||
|
completedAt: undefined,
|
||||||
|
error: "Test execution failed",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle errors gracefully", () => {
|
||||||
|
// Arrange
|
||||||
|
spawnerService.listAgentSessions.mockImplementation(() => {
|
||||||
|
throw new Error("Service unavailable");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
expect(() => controller.listAgents()).toThrow("Failed to list agents: Service unavailable");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("spawn", () => {
|
describe("spawn", () => {
|
||||||
const validRequest = {
|
const validRequest = {
|
||||||
taskId: "task-123",
|
taskId: "task-123",
|
||||||
|
|||||||
@@ -70,6 +70,47 @@ export class AgentsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all agents
|
||||||
|
* @returns Array of all agent sessions with their status
|
||||||
|
*/
|
||||||
|
@Get()
|
||||||
|
listAgents(): {
|
||||||
|
agentId: string;
|
||||||
|
taskId: string;
|
||||||
|
status: string;
|
||||||
|
agentType: string;
|
||||||
|
spawnedAt: string;
|
||||||
|
completedAt?: string;
|
||||||
|
error?: string;
|
||||||
|
}[] {
|
||||||
|
this.logger.log("Received request to list all agents");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get all sessions from spawner service
|
||||||
|
const sessions = this.spawnerService.listAgentSessions();
|
||||||
|
|
||||||
|
// Map to response format
|
||||||
|
const agents = sessions.map((session) => ({
|
||||||
|
agentId: session.agentId,
|
||||||
|
taskId: session.taskId,
|
||||||
|
status: session.state,
|
||||||
|
agentType: session.agentType,
|
||||||
|
spawnedAt: session.spawnedAt.toISOString(),
|
||||||
|
completedAt: session.completedAt?.toISOString(),
|
||||||
|
error: session.error,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.logger.log(`Found ${agents.length.toString()} agents`);
|
||||||
|
|
||||||
|
return agents;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
this.logger.error(`Failed to list agents: ${errorMessage}`);
|
||||||
|
throw new Error(`Failed to list agents: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get agent status
|
* Get agent status
|
||||||
* @param agentId Agent ID to query
|
* @param agentId Agent ID to query
|
||||||
|
|||||||
@@ -7,76 +7,103 @@ import { Bot, Activity, AlertCircle, CheckCircle, Clock } from "lucide-react";
|
|||||||
import type { WidgetProps } from "@mosaic/shared";
|
import type { WidgetProps } from "@mosaic/shared";
|
||||||
|
|
||||||
interface Agent {
|
interface Agent {
|
||||||
id: string;
|
agentId: string;
|
||||||
name: string;
|
taskId: string;
|
||||||
status: "IDLE" | "WORKING" | "WAITING" | "ERROR" | "TERMINATED";
|
status: string;
|
||||||
currentTask?: string;
|
agentType: string;
|
||||||
lastHeartbeat: string;
|
spawnedAt: string;
|
||||||
taskCount: number;
|
completedAt?: string;
|
||||||
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): React.JSX.Element {
|
export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): React.JSX.Element {
|
||||||
const [agents, setAgents] = useState<Agent[]>([]);
|
const [agents, setAgents] = useState<Agent[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
// Mock data for now - will fetch from API later
|
// Fetch agents from orchestrator API
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchAgents = async (): Promise<void> => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setTimeout(() => {
|
setError(null);
|
||||||
setAgents([
|
|
||||||
{
|
try {
|
||||||
id: "1",
|
// Get orchestrator URL from environment or default to localhost
|
||||||
name: "Code Review Agent",
|
const orchestratorUrl = process.env.NEXT_PUBLIC_ORCHESTRATOR_URL ?? "http://localhost:8001";
|
||||||
status: "WORKING",
|
|
||||||
currentTask: "Reviewing PR #123",
|
const response = await fetch(`${orchestratorUrl}/agents`, {
|
||||||
lastHeartbeat: new Date().toISOString(),
|
headers: {
|
||||||
taskCount: 42,
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
{
|
});
|
||||||
id: "2",
|
|
||||||
name: "Documentation Agent",
|
if (!response.ok) {
|
||||||
status: "IDLE",
|
throw new Error(`Failed to fetch agents: ${response.statusText}`);
|
||||||
lastHeartbeat: new Date().toISOString(),
|
}
|
||||||
taskCount: 15,
|
|
||||||
},
|
const data = (await response.json()) as Agent[];
|
||||||
{
|
setAgents(data);
|
||||||
id: "3",
|
} catch (err: unknown) {
|
||||||
name: "Test Runner Agent",
|
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
||||||
status: "ERROR",
|
console.error("Failed to fetch agents:", errorMessage);
|
||||||
currentTask: "Failed to run tests",
|
setError(errorMessage);
|
||||||
lastHeartbeat: new Date(Date.now() - 300000).toISOString(),
|
setAgents([]); // Clear agents on error
|
||||||
taskCount: 28,
|
} finally {
|
||||||
},
|
|
||||||
]);
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, 500);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void fetchAgents();
|
||||||
|
|
||||||
|
// Refresh every 30 seconds
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
void fetchAgents();
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
return (): void => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getStatusIcon = (status: Agent["status"]): React.JSX.Element => {
|
const getStatusIcon = (status: string): React.JSX.Element => {
|
||||||
switch (status) {
|
const statusLower = status.toLowerCase();
|
||||||
case "WORKING":
|
switch (statusLower) {
|
||||||
|
case "running":
|
||||||
|
case "working":
|
||||||
return <Activity className="w-4 h-4 text-blue-500 animate-pulse" />;
|
return <Activity className="w-4 h-4 text-blue-500 animate-pulse" />;
|
||||||
case "IDLE":
|
case "spawning":
|
||||||
return <Clock className="w-4 h-4 text-gray-400" />;
|
case "queued":
|
||||||
case "WAITING":
|
|
||||||
return <Clock className="w-4 h-4 text-yellow-500" />;
|
return <Clock className="w-4 h-4 text-yellow-500" />;
|
||||||
case "ERROR":
|
case "completed":
|
||||||
|
return <CheckCircle className="w-4 h-4 text-green-500" />;
|
||||||
|
case "failed":
|
||||||
|
case "error":
|
||||||
return <AlertCircle className="w-4 h-4 text-red-500" />;
|
return <AlertCircle className="w-4 h-4 text-red-500" />;
|
||||||
case "TERMINATED":
|
case "terminated":
|
||||||
|
case "killed":
|
||||||
return <CheckCircle className="w-4 h-4 text-gray-500" />;
|
return <CheckCircle className="w-4 h-4 text-gray-500" />;
|
||||||
default:
|
default:
|
||||||
return <Clock className="w-4 h-4 text-gray-400" />;
|
return <Clock className="w-4 h-4 text-gray-400" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusText = (status: Agent["status"]): string => {
|
const getStatusText = (status: string): string => {
|
||||||
return status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
|
return status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTimeSinceLastHeartbeat = (timestamp: string): string => {
|
const getAgentName = (agent: Agent): string => {
|
||||||
|
const typeMap: Record<string, string> = {
|
||||||
|
worker: "Worker Agent",
|
||||||
|
reviewer: "Code Review Agent",
|
||||||
|
tester: "Test Runner Agent",
|
||||||
|
};
|
||||||
|
return typeMap[agent.agentType] ?? `${getStatusText(agent.agentType)} Agent`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTimeSinceSpawn = (timestamp: string): string => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const last = new Date(timestamp);
|
const spawned = new Date(timestamp);
|
||||||
const diffMs = now.getTime() - last.getTime();
|
const diffMs = now.getTime() - spawned.getTime();
|
||||||
|
|
||||||
if (diffMs < 60000) return "Just now";
|
if (diffMs < 60000) return "Just now";
|
||||||
if (diffMs < 3600000) return `${String(Math.floor(diffMs / 60000))}m ago`;
|
if (diffMs < 3600000) return `${String(Math.floor(diffMs / 60000))}m ago`;
|
||||||
@@ -86,9 +113,9 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
|
|
||||||
const stats = {
|
const stats = {
|
||||||
total: agents.length,
|
total: agents.length,
|
||||||
working: agents.filter((a) => a.status === "WORKING").length,
|
working: agents.filter((a) => a.status.toLowerCase() === "running").length,
|
||||||
idle: agents.filter((a) => a.status === "IDLE").length,
|
idle: agents.filter((a) => a.status.toLowerCase() === "spawning").length,
|
||||||
error: agents.filter((a) => a.status === "ERROR").length,
|
error: agents.filter((a) => a.status.toLowerCase() === "failed").length,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -99,6 +126,17 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-full">
|
||||||
|
<div className="text-red-500 text-sm">
|
||||||
|
<AlertCircle className="w-4 h-4 inline mr-1" />
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full space-y-3">
|
<div className="flex flex-col h-full space-y-3">
|
||||||
{/* Summary stats */}
|
{/* Summary stats */}
|
||||||
@@ -124,15 +162,15 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
{/* Agent list */}
|
{/* Agent list */}
|
||||||
<div className="flex-1 overflow-auto space-y-2">
|
<div className="flex-1 overflow-auto space-y-2">
|
||||||
{agents.length === 0 ? (
|
{agents.length === 0 ? (
|
||||||
<div className="text-center text-gray-500 text-sm py-4">No agents configured</div>
|
<div className="text-center text-gray-500 text-sm py-4">No agents running</div>
|
||||||
) : (
|
) : (
|
||||||
agents.map((agent) => (
|
agents.map((agent) => (
|
||||||
<div
|
<div
|
||||||
key={agent.id}
|
key={agent.agentId}
|
||||||
className={`p-3 rounded-lg border ${
|
className={`p-3 rounded-lg border ${
|
||||||
agent.status === "ERROR"
|
agent.status.toLowerCase() === "failed"
|
||||||
? "bg-red-50 border-red-200"
|
? "bg-red-50 border-red-200"
|
||||||
: agent.status === "WORKING"
|
: agent.status.toLowerCase() === "running"
|
||||||
? "bg-blue-50 border-blue-200"
|
? "bg-blue-50 border-blue-200"
|
||||||
: "bg-gray-50 border-gray-200"
|
: "bg-gray-50 border-gray-200"
|
||||||
}`}
|
}`}
|
||||||
@@ -140,7 +178,7 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Bot className="w-4 h-4 text-gray-600" />
|
<Bot className="w-4 h-4 text-gray-600" />
|
||||||
<span className="text-sm font-medium text-gray-900">{agent.name}</span>
|
<span className="text-sm font-medium text-gray-900">{getAgentName(agent)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1 text-xs text-gray-500">
|
<div className="flex items-center gap-1 text-xs text-gray-500">
|
||||||
{getStatusIcon(agent.status)}
|
{getStatusIcon(agent.status)}
|
||||||
@@ -148,13 +186,13 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{agent.currentTask && (
|
<div className="text-xs text-gray-600 mb-1">Task: {agent.taskId}</div>
|
||||||
<div className="text-xs text-gray-600 mb-1">{agent.currentTask}</div>
|
|
||||||
)}
|
{agent.error && <div className="text-xs text-red-600 mb-1">{agent.error}</div>}
|
||||||
|
|
||||||
<div className="flex items-center justify-between text-xs text-gray-400">
|
<div className="flex items-center justify-between text-xs text-gray-400">
|
||||||
<span>{agent.taskCount} tasks completed</span>
|
<span>Agent ID: {agent.agentId.slice(0, 8)}...</span>
|
||||||
<span>{getTimeSinceLastHeartbeat(agent.lastHeartbeat)}</span>
|
<span>{getTimeSinceSpawn(agent.spawnedAt)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { render, screen, waitFor } from "@testing-library/react";
|
||||||
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||||
|
import { AgentStatusWidget } from "../AgentStatusWidget";
|
||||||
|
|
||||||
|
describe("AgentStatusWidget", () => {
|
||||||
|
const mockFetch = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
global.fetch = mockFetch as unknown as typeof fetch;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render loading state initially", () => {
|
||||||
|
mockFetch.mockImplementation(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
() => new Promise(() => {}) // Never resolves
|
||||||
|
);
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
expect(screen.getByText("Loading agents...")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fetch and display agents from API", async () => {
|
||||||
|
const mockAgents = [
|
||||||
|
{
|
||||||
|
agentId: "agent-1",
|
||||||
|
taskId: "task-1",
|
||||||
|
status: "running",
|
||||||
|
agentType: "worker",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agentId: "agent-2",
|
||||||
|
taskId: "task-2",
|
||||||
|
status: "completed",
|
||||||
|
agentType: "reviewer",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
completedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: () => Promise.resolve(mockAgents),
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("Worker Agent")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Code Review Agent")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("Task: task-1")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Task: task-2")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display error message when fetch fails", async () => {
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
ok: false,
|
||||||
|
statusText: "Internal Server Error",
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText(/Failed to fetch agents: Internal Server Error/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display no agents message when list is empty", async () => {
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: () => Promise.resolve([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("No agents running")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display agent error messages", async () => {
|
||||||
|
const mockAgents = [
|
||||||
|
{
|
||||||
|
agentId: "agent-1",
|
||||||
|
taskId: "task-1",
|
||||||
|
status: "failed",
|
||||||
|
agentType: "tester",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
error: "Test execution failed",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: () => Promise.resolve(mockAgents),
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("Test execution failed")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display correct stats summary", async () => {
|
||||||
|
const mockAgents = [
|
||||||
|
{
|
||||||
|
agentId: "agent-1",
|
||||||
|
taskId: "task-1",
|
||||||
|
status: "running",
|
||||||
|
agentType: "worker",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agentId: "agent-2",
|
||||||
|
taskId: "task-2",
|
||||||
|
status: "running",
|
||||||
|
agentType: "reviewer",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
agentId: "agent-3",
|
||||||
|
taskId: "task-3",
|
||||||
|
status: "failed",
|
||||||
|
agentType: "tester",
|
||||||
|
spawnedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
json: () => Promise.resolve(mockAgents),
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<AgentStatusWidget id="test-widget" config={{}} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
// Check stats: 3 total, 2 working, 0 idle, 1 error
|
||||||
|
const stats = screen.getAllByText(/^[0-9]+$/);
|
||||||
|
expect(stats[0]).toHaveTextContent("3"); // Total
|
||||||
|
expect(stats[1]).toHaveTextContent("2"); // Working
|
||||||
|
expect(stats[2]).toHaveTextContent("0"); // Idle
|
||||||
|
expect(stats[3]).toHaveTextContent("1"); // Error
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:25:45
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1225_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 2
|
||||||
|
**Generated:** 2026-02-05 12:25:47
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1225_2_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 3
|
||||||
|
**Generated:** 2026-02-05 12:25:57
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1225_3_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:27:48
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1227_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:28:48
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1228_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 2
|
||||||
|
**Generated:** 2026-02-05 12:28:50
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1228_2_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.spec.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 3
|
||||||
|
**Generated:** 2026-02-05 12:28:52
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.spec.ts_20260205-1228_3_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:25:37
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.ts_20260205-1225_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:27:25
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.ts_20260205-1227_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 2
|
||||||
|
**Generated:** 2026-02-05 12:27:27
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.ts_20260205-1227_2_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/orchestrator/src/api/agents/agents.controller.ts
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:28:41
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-orchestrator-src-api-agents-agents.controller.ts_20260205-1228_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:26:19
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1226_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 2
|
||||||
|
**Generated:** 2026-02-05 12:26:34
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1226_2_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 3
|
||||||
|
**Generated:** 2026-02-05 12:26:36
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1226_3_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 4
|
||||||
|
**Generated:** 2026-02-05 12:26:46
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1226_4_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:27:48
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1227_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/AgentStatusWidget.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:29:51
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-AgentStatusWidget.tsx_20260205-1229_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/**tests**/AgentStatusWidget.test.tsx
|
||||||
|
**Tool Used:** Write
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:27:06
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-__tests__-AgentStatusWidget.test.tsx_20260205-1227_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/**tests**/AgentStatusWidget.test.tsx
|
||||||
|
**Tool Used:** Write
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:30:26
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-__tests__-AgentStatusWidget.test.tsx_20260205-1230_1_remediation_needed.md"
|
||||||
|
```
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# QA Remediation Report
|
||||||
|
|
||||||
|
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/components/widgets/**tests**/AgentStatusWidget.test.tsx
|
||||||
|
**Tool Used:** Edit
|
||||||
|
**Epic:** general
|
||||||
|
**Iteration:** 1
|
||||||
|
**Generated:** 2026-02-05 12:31:04
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Pending QA validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
This report was created by the QA automation hook.
|
||||||
|
To process this report, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-components-widgets-__tests__-AgentStatusWidget.test.tsx_20260205-1231_1_remediation_needed.md"
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user