#!/usr/bin/env python3 import os BASE_DIR = "/Users/jakeshore/.clawdbot/workspace/mcpengine-repo/servers/xero/src/apps" # Define remaining apps with their specific data apps = [ { "name": "bank-feed", "title": "Bank Feed", "subtitle": "Bank transactions and reconciliation", "icon": "šŸ¦", "mock_type": "BankTransaction", "mock_data": [ "{ id: '1', date: '2024-01-15', description: 'Client Payment - INV-001', type: 'RECEIVE', amount: 12500.00, status: 'MATCHED' }", "{ id: '2', date: '2024-01-16', description: 'Office Supplies', type: 'SPEND', amount: -350.00, status: 'UNMATCHED' }", "{ id: '3', date: '2024-01-17', description: 'Monthly Rent', type: 'SPEND', amount: -2500.00, status: 'MATCHED' }", "{ id: '4', date: '2024-01-18', description: 'Client Payment - INV-002', type: 'RECEIVE', amount: 8750.00, status: 'PENDING' }", "{ id: '5', date: '2024-01-20', description: 'Utility Bill', type: 'SPEND', amount: -450.00, status: 'UNMATCHED' }", ], "columns": ["Date", "Description", "Type", "Amount", "Status"], "stats": ["Total Transactions", "Matched", "Unmatched", "Pending"] }, { "name": "payment-tracker", "title": "Payment Tracker", "subtitle": "Track payments, prepayments, and overpayments", "icon": "šŸ’³", "mock_type": "Payment", "mock_data": [ "{ id: '1', date: '2024-01-15', invoice: 'INV-0001', contact: 'Acme Corp', type: 'PAYMENT', amount: 12500.00, status: 'AUTHORISED' }", "{ id: '2', date: '2024-01-18', invoice: 'INV-0002', contact: 'Tech Solutions', type: 'PREPAYMENT', amount: 5000.00, status: 'AUTHORISED' }", "{ id: '3', date: '2024-01-20', invoice: 'INV-0003', contact: 'Global Services', type: 'OVERPAYMENT', amount: 1200.00, status: 'PENDING' }", "{ id: '4', date: '2024-01-22', invoice: 'BILL-0001', contact: 'Office Supplies', type: 'PAYMENT', amount: 3500.00, status: 'AUTHORISED' }", "{ id: '5', date: '2024-01-25', invoice: 'INV-0004', contact: 'StartUp Co', type: 'PAYMENT', amount: 5200.00, status: 'PENDING' }", ], "columns": ["Date", "Invoice", "Contact", "Type", "Amount", "Status"], "stats": ["Total Payments", "Authorised", "Pending", "Prepayments"] }, { "name": "credit-note-manager", "title": "Credit Note Manager", "subtitle": "Manage credit notes and allocations", "icon": "šŸ“", "mock_type": "CreditNote", "mock_data": [ "{ id: '1', creditNoteNumber: 'CN-0001', contact: 'Acme Corp', date: '2024-01-10', total: 1250.00, remaining: 1250.00, status: 'AUTHORISED' }", "{ id: '2', creditNoteNumber: 'CN-0002', contact: 'Tech Solutions', date: '2024-01-12', total: 750.00, remaining: 0, status: 'PAID' }", "{ id: '3', creditNoteNumber: 'CN-0003', contact: 'Global Services', date: '2024-01-15', total: 2200.00, remaining: 2200.00, status: 'DRAFT' }", "{ id: '4', creditNoteNumber: 'CN-0004', contact: 'StartUp Co', date: '2024-01-18', total: 500.00, remaining: 500.00, status: 'SUBMITTED' }", "{ id: '5', creditNoteNumber: 'CN-0005', contact: 'Enterprise LLC', date: '2024-01-20', total: 3100.00, remaining: 1500.00, status: 'AUTHORISED' }", ], "columns": ["Credit Note #", "Contact", "Date", "Total", "Remaining", "Status"], "stats": ["Total Credit Notes", "Outstanding", "Allocated", "Draft"] }, { "name": "purchase-orders", "title": "Purchase Orders", "subtitle": "Track PO list, status, and approvals", "icon": "šŸ›’", "mock_type": "PurchaseOrder", "mock_data": [ "{ id: '1', poNumber: 'PO-0001', supplier: 'Office Supplies Co', date: '2024-01-10', total: 3500.00, status: 'AUTHORISED' }", "{ id: '2', poNumber: 'PO-0002', supplier: 'Tech Vendor', date: '2024-01-12', total: 8900.00, status: 'BILLED' }", "{ id: '3', poNumber: 'PO-0003', supplier: 'Marketing Agency', date: '2024-01-15', total: 6750.00, status: 'DRAFT' }", "{ id: '4', poNumber: 'PO-0004', supplier: 'Consulting Group', date: '2024-01-18', total: 15000.00, status: 'SUBMITTED' }", "{ id: '5', poNumber: 'PO-0005', supplier: 'Equipment Rentals', date: '2024-01-20', total: 4200.00, status: 'AUTHORISED' }", ], "columns": ["PO Number", "Supplier", "Date", "Total", "Status"], "stats": ["Total POs", "Authorised", "Billed", "Draft"] }, { "name": "quote-builder", "title": "Quote Builder", "subtitle": "Manage quotes and convert to invoices", "icon": "šŸ’¼", "mock_type": "Quote", "mock_data": [ "{ id: '1', quoteNumber: 'QT-0001', contact: 'Acme Corp', date: '2024-01-10', expiryDate: '2024-02-10', total: 15000.00, status: 'DRAFT' }", "{ id: '2', quoteNumber: 'QT-0002', contact: 'Tech Solutions', date: '2024-01-12', expiryDate: '2024-02-12', total: 8750.00, status: 'SENT' }", "{ id: '3', quoteNumber: 'QT-0003', contact: 'Global Services', date: '2024-01-15', expiryDate: '2024-02-15', total: 22100.00, status: 'ACCEPTED' }", "{ id: '4', quoteNumber: 'QT-0004', contact: 'StartUp Co', date: '2024-01-18', expiryDate: '2024-02-18', total: 5200.00, status: 'DECLINED' }", "{ id: '5', quoteNumber: 'QT-0005', contact: 'Enterprise LLC', date: '2024-01-20', expiryDate: '2024-02-20', total: 18900.00, status: 'SENT' }", ], "columns": ["Quote #", "Contact", "Date", "Expiry Date", "Total", "Status"], "stats": ["Total Quotes", "Sent", "Accepted", "Draft"] }, ] # Template files MAIN_TSX = '''import React, { Suspense, Component, ErrorInfo, ReactNode } from 'react'; import { createRoot } from 'react-dom/client'; const App = React.lazy(() => import('./App')); interface ErrorBoundaryProps { children: ReactNode; } interface ErrorBoundaryState { hasError: boolean; error?: Error; } class ErrorBoundary extends Component { constructor(props: ErrorBoundaryProps) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error: Error): ErrorBoundaryState { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: ErrorInfo) { console.error('Error caught by boundary:', error, errorInfo); } render() { if (this.state.hasError) { return (

Something went wrong

{this.state.error?.message}

); } return this.props.children; } } const LoadingSkeleton = () => (
); const container = document.getElementById('root'); if (container) { const root = createRoot(container); root.render( }> ); } ''' # Generate files for each app for app in apps: app_dir = os.path.join(BASE_DIR, app["name"]) # Create index.html html_content = f''' {app["title"]} - Xero MCP
''' with open(os.path.join(app_dir, "index.html"), "w") as f: f.write(html_content) # Create main.tsx with open(os.path.join(app_dir, "main.tsx"), "w") as f: f.write(MAIN_TSX) # Copy styles.css from template os.system(f"cp {BASE_DIR}/invoice-dashboard/styles.css {app_dir}/styles.css") print(f"āœ… Created files for {app['name']}") print("\n✨ Batch creation complete!")