refactor: 移除 Team 和 Swarm 协作功能
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
功能论证结论:Team(团队)和 Swarm(协作)为零后端支持的 纯前端 localStorage 空壳,Pipeline 系统已完全覆盖其全部能力。 删除 16 个文件,约 7,950 行代码: - 5 个组件:TeamCollaborationView, TeamOrchestrator, TeamList, DevQALoop, SwarmDashboard - 1 个 Store:teamStore.ts - 3 个 Client/库:team-client.ts, useTeamEvents.ts, agent-swarm.ts - 1 个类型文件:team.ts - 4 个测试文件 - 1 个文档(归档 swarm-coordination.md) 修改 4 个文件: - Sidebar.tsx:移除"团队"和"协作"导航项 - App.tsx:移除 team/swarm 视图路由 - types/index.ts:移除 team 类型导出 - chatStore.ts:移除 dispatchSwarmTask 方法 更新 CHANGELOG.md 和功能文档 README.md
This commit is contained in:
@@ -1,373 +0,0 @@
|
||||
/**
|
||||
* Team Store Tests
|
||||
*
|
||||
* Tests for multi-agent team collaboration state management.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { useTeamStore } from '../../src/store/teamStore';
|
||||
import type { Team, TeamMember, TeamTask, CreateTeamRequest, AddTeamTaskRequest, TeamMemberRole } from '../../src/types/team';
|
||||
import { localStorageMock } from '../setup';
|
||||
|
||||
// Mock fetch globally
|
||||
const mockFetch = vi.fn();
|
||||
const originalFetch = global.fetch;
|
||||
|
||||
describe('teamStore', () => {
|
||||
beforeEach(() => {
|
||||
global.fetch = mockFetch;
|
||||
mockFetch.mockClear();
|
||||
localStorageMock.clear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.fetch = originalFetch;
|
||||
mockFetch.mockReset();
|
||||
});
|
||||
|
||||
describe('Initial State', () => {
|
||||
it('should have correct initial state', () => {
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.teams).toEqual([]);
|
||||
expect(store.activeTeam).toBeNull();
|
||||
expect(store.metrics).toBeNull();
|
||||
expect(store.isLoading).toBe(false);
|
||||
expect(store.error).toBeNull();
|
||||
expect(store.selectedTaskId).toBeNull();
|
||||
expect(store.selectedMemberId).toBeNull();
|
||||
expect(store.recentEvents).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadTeams', () => {
|
||||
// Note: This test is skipped because the zustand persist middleware
|
||||
// interferes with manual localStorage manipulation in tests.
|
||||
// The persist middleware handles loading automatically.
|
||||
it.skip('should load teams from localStorage', async () => {
|
||||
const mockTeams: Team[] = [
|
||||
{
|
||||
id: 'team-1',
|
||||
name: 'Test Team',
|
||||
members: [],
|
||||
tasks: [],
|
||||
pattern: 'sequential',
|
||||
activeLoops: [],
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
updatedAt: '2024-01-01T00:00:00Z',
|
||||
},
|
||||
];
|
||||
// Clear any existing data
|
||||
localStorageMock.clear();
|
||||
// Set localStorage in the format that zustand persist middleware uses
|
||||
localStorageMock.setItem('zclaw-teams', JSON.stringify({
|
||||
state: {
|
||||
teams: mockTeams,
|
||||
activeTeam: null
|
||||
},
|
||||
version: 0
|
||||
}));
|
||||
|
||||
await useTeamStore.getState().loadTeams();
|
||||
|
||||
const store = useTeamStore.getState();
|
||||
// Check that teams were loaded
|
||||
expect(store.teams).toHaveLength(1);
|
||||
expect(store.teams[0].name).toBe('Test Team');
|
||||
expect(store.isLoading).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createTeam', () => {
|
||||
it('should create a new team with members', async () => {
|
||||
const request: CreateTeamRequest = {
|
||||
name: 'Dev Team',
|
||||
description: 'Development team',
|
||||
memberAgents: [
|
||||
{ agentId: 'agent-1', role: 'developer' },
|
||||
{ agentId: 'agent-2', role: 'reviewer' },
|
||||
],
|
||||
pattern: 'review_loop',
|
||||
};
|
||||
const team = await useTeamStore.getState().createTeam(request);
|
||||
expect(team).not.toBeNull();
|
||||
expect(team.name).toBe('Dev Team');
|
||||
expect(team.description).toBe('Development team');
|
||||
expect(team.pattern).toBe('review_loop');
|
||||
expect(team.members).toHaveLength(2);
|
||||
expect(team.status).toBe('active');
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.teams).toHaveLength(1);
|
||||
expect(store.activeTeam?.id).toBe(team.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteTeam', () => {
|
||||
it('should delete a team', async () => {
|
||||
// First create a team
|
||||
const request: CreateTeamRequest = {
|
||||
name: 'Team to Delete',
|
||||
memberAgents: [],
|
||||
pattern: 'sequential',
|
||||
};
|
||||
await useTeamStore.getState().createTeam(request);
|
||||
// Then delete it
|
||||
const result = await useTeamStore.getState().deleteTeam('team-to-delete-id');
|
||||
expect(result).toBe(true);
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.teams.find(t => t.id === 'team-to-delete-id')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setActiveTeam', () => {
|
||||
it('should set active team and update metrics', () => {
|
||||
const team: Team = {
|
||||
id: 'team-1',
|
||||
name: 'Test Team',
|
||||
members: [],
|
||||
tasks: [],
|
||||
pattern: 'sequential',
|
||||
activeLoops: [],
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
};
|
||||
useTeamStore.getState().setActiveTeam(team);
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.activeTeam).toEqual(team);
|
||||
expect(store.metrics).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMember', () => {
|
||||
let team: Team;
|
||||
beforeEach(async () => {
|
||||
const request: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [],
|
||||
pattern: 'sequential',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(request))!;
|
||||
});
|
||||
it('should add a member to team', async () => {
|
||||
const member = await useTeamStore.getState().addMember(team.id, 'agent-1', 'developer');
|
||||
expect(member).not.toBeNull();
|
||||
expect(member.agentId).toBe('agent-1');
|
||||
expect(member.role).toBe('developer');
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
expect(updatedTeam?.members).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMember', () => {
|
||||
let team: Team;
|
||||
let memberId: string;
|
||||
beforeEach(async () => {
|
||||
const request: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [{ agentId: 'agent-1', role: 'developer' }],
|
||||
pattern: 'sequential',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(request))!;
|
||||
memberId = team.members[0].id;
|
||||
});
|
||||
it('should remove a member from team', async () => {
|
||||
const result = await useTeamStore.getState().removeMember(team.id, memberId);
|
||||
expect(result).toBe(true);
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
expect(updatedTeam?.members).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addTask', () => {
|
||||
let team: Team;
|
||||
beforeEach(async () => {
|
||||
const request: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [],
|
||||
pattern: 'sequential',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(request))!;
|
||||
});
|
||||
it('should add a task to team', async () => {
|
||||
const taskRequest: AddTeamTaskRequest = {
|
||||
teamId: team.id,
|
||||
title: 'Test Task',
|
||||
description: 'Test task description',
|
||||
priority: 'high',
|
||||
type: 'implementation',
|
||||
};
|
||||
const task = await useTeamStore.getState().addTask(taskRequest);
|
||||
expect(task).not.toBeNull();
|
||||
expect(task.title).toBe('Test Task');
|
||||
expect(task.status).toBe('pending');
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
expect(updatedTeam?.tasks).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateTaskStatus', () => {
|
||||
let team: Team;
|
||||
let taskId: string;
|
||||
beforeEach(async () => {
|
||||
const teamRequest: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [],
|
||||
pattern: 'sequential',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(teamRequest))!;
|
||||
const taskRequest: AddTeamTaskRequest = {
|
||||
teamId: team.id,
|
||||
title: 'Test Task',
|
||||
priority: 'medium',
|
||||
type: 'implementation',
|
||||
};
|
||||
const task = await useTeamStore.getState().addTask(taskRequest);
|
||||
taskId = task!.id;
|
||||
});
|
||||
it('should update task status to in_progress', async () => {
|
||||
const result = await useTeamStore.getState().updateTaskStatus(team.id, taskId, 'in_progress');
|
||||
expect(result).toBe(true);
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
const updatedTask = updatedTeam?.tasks.find(t => t.id === taskId);
|
||||
expect(updatedTask?.status).toBe('in_progress');
|
||||
expect(updatedTask?.startedAt).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('startDevQALoop', () => {
|
||||
let team: Team;
|
||||
let taskId: string;
|
||||
let memberId: string;
|
||||
beforeEach(async () => {
|
||||
const teamRequest: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [
|
||||
{ agentId: 'dev-agent', role: 'developer' },
|
||||
{ agentId: 'qa-agent', role: 'reviewer' },
|
||||
],
|
||||
pattern: 'review_loop',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(teamRequest))!;
|
||||
const taskRequest: AddTeamTaskRequest = {
|
||||
teamId: team.id,
|
||||
title: 'Test Task',
|
||||
priority: 'high',
|
||||
type: 'implementation',
|
||||
assigneeId: team.members[0].id,
|
||||
};
|
||||
const task = await useTeamStore.getState().addTask(taskRequest);
|
||||
taskId = task!.id;
|
||||
memberId = team.members[0].id;
|
||||
});
|
||||
it('should start a Dev-QA loop', async () => {
|
||||
const loop = await useTeamStore.getState().startDevQALoop(
|
||||
team.id,
|
||||
taskId,
|
||||
team.members[0].id,
|
||||
team.members[1].id
|
||||
);
|
||||
expect(loop).not.toBeNull();
|
||||
expect(loop.state).toBe('developing');
|
||||
expect(loop.developerId).toBe(team.members[0].id);
|
||||
expect(loop.reviewerId).toBe(team.members[1].id);
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
expect(updatedTeam?.activeLoops).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('submitReview', () => {
|
||||
let team: Team;
|
||||
let loop: any;
|
||||
beforeEach(async () => {
|
||||
const teamRequest: CreateTeamRequest = {
|
||||
name: 'Test Team',
|
||||
memberAgents: [
|
||||
{ agentId: 'dev-agent', role: 'developer' },
|
||||
{ agentId: 'qa-agent', role: 'reviewer' },
|
||||
],
|
||||
pattern: 'review_loop',
|
||||
};
|
||||
team = (await useTeamStore.getState().createTeam(teamRequest))!;
|
||||
const taskRequest: AddTeamTaskRequest = {
|
||||
teamId: team.id,
|
||||
title: 'Test Task',
|
||||
priority: 'high',
|
||||
type: 'implementation',
|
||||
assigneeId: team.members[0].id,
|
||||
};
|
||||
const task = await useTeamStore.getState().addTask(taskRequest);
|
||||
loop = await useTeamStore.getState().startDevQALoop(
|
||||
team.id,
|
||||
task!.id,
|
||||
team.members[0].id,
|
||||
team.members[1].id
|
||||
);
|
||||
});
|
||||
it('should submit review and update loop state', async () => {
|
||||
const feedback = {
|
||||
verdict: 'approved',
|
||||
comments: ['Good work!'],
|
||||
issues: [],
|
||||
};
|
||||
const result = await useTeamStore.getState().submitReview(team.id, loop.id, feedback);
|
||||
expect(result).toBe(true);
|
||||
const store = useTeamStore.getState();
|
||||
const updatedTeam = store.teams.find(t => t.id === team.id);
|
||||
const updatedLoop = updatedTeam?.activeLoops.find(l => l.id === loop.id);
|
||||
expect(updatedLoop?.state).toBe('approved');
|
||||
});
|
||||
});
|
||||
|
||||
describe('addEvent', () => {
|
||||
it('should add event to recent events', () => {
|
||||
const event = {
|
||||
type: 'task_completed',
|
||||
teamId: 'team-1',
|
||||
sourceAgentId: 'agent-1',
|
||||
payload: { taskId: 'task-1' },
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
useTeamStore.getState().addEvent(event);
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.recentEvents).toHaveLength(1);
|
||||
expect(store.recentEvents[0]).toEqual(event);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearEvents', () => {
|
||||
it('should clear all events', () => {
|
||||
const event = {
|
||||
type: 'task_completed',
|
||||
teamId: 'team-1',
|
||||
sourceAgentId: 'agent-1',
|
||||
payload: {},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
useTeamStore.getState().addEvent(event);
|
||||
useTeamStore.getState().clearEvents();
|
||||
const store = useTeamStore.getState();
|
||||
expect(store.recentEvents).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UI Actions', () => {
|
||||
it('should set selected task', () => {
|
||||
useTeamStore.getState().setSelectedTask('task-1');
|
||||
expect(useTeamStore.getState().selectedTaskId).toBe('task-1');
|
||||
});
|
||||
it('should set selected member', () => {
|
||||
useTeamStore.getState().setSelectedMember('member-1');
|
||||
expect(useTeamStore.getState().selectedMemberId).toBe('member-1');
|
||||
});
|
||||
it('should clear error', () => {
|
||||
useTeamStore.setState({ error: 'Test error' });
|
||||
useTeamStore.getState().clearError();
|
||||
expect(useTeamStore.getState().error).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user