'use client'; import React, { useCallback, useEffect, useState } from 'react'; import { ReactFlowProvider } from '@xyflow/react'; import { Sparkles, FlaskConical, Rocket, Plus, } from 'lucide-react'; import { ToolCanvas } from '../../../../components/canvas/ToolCanvas'; import { ToolInspector } from '../../../../components/inspector/ToolInspector'; import { useCanvasState } from '../../../../hooks/useCanvasState'; import type { ToolDefinition } from '@mcpengine/ai-pipeline/types'; import type { ToolNodeData } from '../../../../components/canvas/ToolNode'; // Mock data for development — replaced by API calls in production const MOCK_TOOLS: ToolDefinition[] = [ { name: 'list_contacts', description: 'Retrieve a paginated list of contacts with optional filtering by tags, dates, and custom fields.', method: 'GET', endpoint: '/contacts', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Max results to return' }, offset: { type: 'number', description: 'Pagination offset' }, tag: { type: 'string', description: 'Filter by tag' }, }, required: [], }, annotations: { readOnlyHint: true, idempotentHint: true }, }, { name: 'create_contact', description: 'Create a new contact with the provided information.', method: 'POST', endpoint: '/contacts', inputSchema: { type: 'object', properties: { email: { type: 'string', description: 'Contact email address' }, name: { type: 'string', description: 'Full name' }, phone: { type: 'string', description: 'Phone number' }, }, required: ['email', 'name'], }, }, { name: 'delete_contact', description: 'Permanently delete a contact by their ID. This action cannot be undone.', method: 'DELETE', endpoint: '/contacts/{id}', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Contact ID' }, }, required: ['id'], }, annotations: { destructiveHint: true }, }, { name: 'update_contact', description: 'Update an existing contact\'s information.', method: 'PUT', endpoint: '/contacts/{id}', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Contact ID' }, email: { type: 'string', description: 'Updated email' }, name: { type: 'string', description: 'Updated name' }, }, required: ['id'], }, annotations: { idempotentHint: true }, }, ]; export default function ProjectEditorPage() { const [tools, setTools] = useState(MOCK_TOOLS); const { selectedNodeId, inspectorOpen, nodes, initializeFromTools, selectNode, updateTool, removeTool, } = useCanvasState(); // Initialize canvas from tools useEffect(() => { initializeFromTools(tools); }, []); // eslint-disable-line react-hooks/exhaustive-deps // Get selected tool const selectedTool = selectedNodeId ? (nodes.find((n) => n.id === selectedNodeId)?.data as ToolNodeData | undefined)?.tool : null; const handleToolSelect = useCallback( (toolName: string | null) => { selectNode(toolName); }, [selectNode] ); const handleToolsChange = useCallback((updated: ToolDefinition[]) => { setTools(updated); }, []); const handleToolChange = useCallback( (updatedTool: ToolDefinition) => { if (!selectedNodeId) return; updateTool(selectedNodeId, updatedTool); setTools((prev) => prev.map((t) => (t.name === selectedNodeId ? updatedTool : t)) ); }, [selectedNodeId, updateTool] ); const handleToolDelete = useCallback( (toolName: string) => { removeTool(toolName); setTools((prev) => prev.filter((t) => t.name !== toolName)); }, [removeTool] ); const handleCloseInspector = useCallback(() => { selectNode(null); }, [selectNode]); return (
{/* Top Bar */}

Project Editor

{tools.length} tools
{/* Main Content */}
{/* Canvas */}
{/* Inspector Panel — slides in from right */}
{selectedTool && ( )}
); }