mirror of
https://github.com/claude-did-this/claude-hub.git
synced 2026-02-14 19:30:02 +01:00
* feat: Implement Claude orchestration provider for parallel session management - Add ClaudeWebhookProvider implementing the webhook provider interface - Create orchestration system for running multiple Claude containers in parallel - Implement smart task decomposition to break complex projects into workstreams - Add session management with dependency tracking between sessions - Support multiple execution strategies (parallel, sequential, wait_for_core) - Create comprehensive test suite for all components - Add documentation for Claude orchestration API and usage This enables super-charged Claude capabilities for the MCP hackathon by allowing multiple Claude instances to work on different aspects of a project simultaneously, with intelligent coordination and result aggregation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Add session management endpoints for MCP integration - Add SessionHandler for individual session CRUD operations - Create endpoints: session.create, session.get, session.list, session.start, session.output - Fix Claude invocation in Docker containers using proper claude chat command - Add volume mounts for persistent storage across session lifecycle - Simplify OrchestrationHandler to create single coordination sessions - Update documentation with comprehensive MCP integration examples - Add comprehensive unit and integration tests for new endpoints - Support dependencies and automatic session queuing/starting This enables Claude Desktop to orchestrate multiple Claude Code sessions via MCP Server tools. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Update ClaudeWebhookProvider validation for session endpoints - Make project fields optional for session management operations - Add validation for session.create requiring session field - Update tests to match new validation rules - Fix failing CI tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Use Promise.reject for validation errors in parsePayload - Convert synchronous throws to Promise.reject for async consistency - Fixes failing unit tests expecting rejected promises 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Mock SessionManager in integration tests to avoid Docker calls in CI - Add SessionManager mock to prevent Docker operations during tests - Fix claude-webhook.test.ts to use proper test setup and payload structure - Ensure all integration tests can run without Docker dependency - Fix payload structure to include 'data' wrapper 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Mock child_process to prevent Docker calls in CI tests - Mock execSync and spawn at child_process level to prevent any Docker commands - This ensures tests work in CI environment without Docker - Tests now pass both locally and in CI Docker build 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Address PR review comments and fix linter warnings - Move @types/uuid to devDependencies - Replace timestamp+Math.random with crypto.randomUUID() for better uniqueness - Extract magic number into EXTRA_SESSIONS_COUNT constant - Update determineStrategy return type to use literal union - Fix unnecessary optional chaining warnings - Handle undefined labels in GitHub transformers - Make TaskDecomposer.decompose synchronous - Add proper eslint-disable comments for intentional sync methods - Fix all TypeScript and formatting issues * fix: Mock SessionManager in integration tests to prevent Docker calls in CI - Add SessionManager mocks to claude-session.test.ts - Add SessionManager mocks to claude-webhook.test.ts - Prevents 500 errors when running tests in CI without Docker - All integration tests now pass without requiring Docker runtime * fix: Run only unit tests in Docker builds to avoid Docker-in-Docker issues - Change test stage to run 'npm run test:unit' instead of 'npm test' - Skips integration tests that require Docker runtime - Prevents CI failures in Docker container builds - Integration tests still run in regular CI workflow * fix: Use Dockerfile CMD for tests in Docker build CI - Remove explicit 'npm test' command from docker run - Let Docker use the CMD defined in Dockerfile (npm run test:unit) - This ensures consistency and runs only unit tests in Docker builds --------- Co-authored-by: Claude <noreply@anthropic.com>
187 lines
5.7 KiB
TypeScript
187 lines
5.7 KiB
TypeScript
import { OrchestrationHandler } from '../../../../../src/providers/claude/handlers/OrchestrationHandler';
|
|
import type { SessionManager } from '../../../../../src/providers/claude/services/SessionManager';
|
|
import type { ClaudeWebhookPayload } from '../../../../../src/providers/claude/ClaudeWebhookProvider';
|
|
import type { WebhookContext } from '../../../../../src/types/webhook';
|
|
|
|
// Mock the services
|
|
jest.mock('../../../../../src/providers/claude/services/SessionManager');
|
|
|
|
describe('OrchestrationHandler', () => {
|
|
let handler: OrchestrationHandler;
|
|
let mockSessionManager: jest.Mocked<SessionManager>;
|
|
let mockContext: WebhookContext;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
handler = new OrchestrationHandler();
|
|
mockSessionManager = (handler as any).sessionManager;
|
|
mockContext = {
|
|
provider: 'claude',
|
|
timestamp: new Date()
|
|
};
|
|
});
|
|
|
|
describe('canHandle', () => {
|
|
it('should handle orchestrate events', () => {
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build API'
|
|
}
|
|
},
|
|
metadata: {}
|
|
};
|
|
|
|
expect(handler.canHandle(payload)).toBe(true);
|
|
});
|
|
|
|
it('should not handle session events', () => {
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'session.create',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Manage session'
|
|
}
|
|
} as any,
|
|
metadata: {}
|
|
};
|
|
|
|
expect(handler.canHandle(payload)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('handle', () => {
|
|
it('should create orchestration session and start it by default', async () => {
|
|
mockSessionManager.createContainer.mockResolvedValue('container-123');
|
|
mockSessionManager.startSession.mockResolvedValue();
|
|
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build a REST API with authentication'
|
|
}
|
|
},
|
|
metadata: {}
|
|
};
|
|
|
|
const response = await handler.handle(payload, mockContext);
|
|
|
|
expect(response.success).toBe(true);
|
|
expect(response.message).toBe('Orchestration session created');
|
|
expect(response.data).toMatchObject({
|
|
status: 'initiated',
|
|
summary: 'Created orchestration session for owner/repo'
|
|
});
|
|
|
|
// Verify session creation
|
|
const createdSession = mockSessionManager.createContainer.mock.calls[0][0];
|
|
expect(createdSession).toMatchObject({
|
|
type: 'coordination',
|
|
status: 'pending',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build a REST API with authentication'
|
|
},
|
|
dependencies: []
|
|
});
|
|
|
|
// Verify session was started
|
|
expect(mockSessionManager.startSession).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should use custom session type when provided', async () => {
|
|
mockSessionManager.createContainer.mockResolvedValue('container-123');
|
|
mockSessionManager.startSession.mockResolvedValue();
|
|
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
sessionType: 'analysis',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Analyze codebase structure'
|
|
}
|
|
} as any,
|
|
metadata: {}
|
|
};
|
|
|
|
const response = await handler.handle(payload, mockContext);
|
|
|
|
expect(response.success).toBe(true);
|
|
|
|
const createdSession = mockSessionManager.createContainer.mock.calls[0][0];
|
|
expect(createdSession.type).toBe('analysis');
|
|
});
|
|
|
|
it('should not start session when autoStart is false', async () => {
|
|
mockSessionManager.createContainer.mockResolvedValue('container-123');
|
|
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
autoStart: false,
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build API'
|
|
}
|
|
} as any,
|
|
metadata: {}
|
|
};
|
|
|
|
const response = await handler.handle(payload, mockContext);
|
|
|
|
expect(response.success).toBe(true);
|
|
expect(mockSessionManager.createContainer).toHaveBeenCalled();
|
|
expect(mockSessionManager.startSession).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should handle errors gracefully', async () => {
|
|
mockSessionManager.createContainer.mockRejectedValue(new Error('Docker error'));
|
|
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build API'
|
|
}
|
|
},
|
|
metadata: {}
|
|
};
|
|
|
|
const response = await handler.handle(payload, mockContext);
|
|
|
|
expect(response.success).toBe(false);
|
|
expect(response.error).toBe('Docker error');
|
|
});
|
|
|
|
it('should generate unique orchestration IDs', async () => {
|
|
mockSessionManager.createContainer.mockResolvedValue('container-123');
|
|
|
|
const payload: ClaudeWebhookPayload = {
|
|
data: {
|
|
type: 'orchestrate',
|
|
autoStart: false,
|
|
project: {
|
|
repository: 'owner/repo',
|
|
requirements: 'Build API'
|
|
}
|
|
} as any,
|
|
metadata: {}
|
|
};
|
|
|
|
const response1 = await handler.handle(payload, mockContext);
|
|
const response2 = await handler.handle(payload, mockContext);
|
|
|
|
expect(response1.data?.orchestrationId).toBeDefined();
|
|
expect(response2.data?.orchestrationId).toBeDefined();
|
|
expect(response1.data?.orchestrationId).not.toBe(response2.data?.orchestrationId);
|
|
});
|
|
});
|
|
});
|