dev3000 0.0.89 → 0.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-environment.d.ts.map +1 -1
- package/dist/dev-environment.js +13 -7
- package/dist/dev-environment.js.map +1 -1
- package/mcp-server/.next/BUILD_ID +1 -1
- package/mcp-server/.next/build-manifest.json +2 -2
- package/mcp-server/.next/fallback-build-manifest.json +2 -2
- package/mcp-server/.next/next-minimal-server.js.nft.json +1 -1
- package/mcp-server/.next/next-server.js.nft.json +1 -1
- package/mcp-server/.next/prerender-manifest.json +3 -3
- package/mcp-server/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_global-error.html +2 -2
- package/mcp-server/.next/server/app/_global-error.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_not-found.html +1 -1
- package/mcp-server/.next/server/app/_not-found.rsc +1 -1
- package/mcp-server/.next/server/app/api/jank/[session]/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/append/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/head/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/list/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/rotate/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/stream/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/tail/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/orchestrator/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/screenshots/[filename]/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/screenshots/list/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/tools/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/index.html +1 -1
- package/mcp-server/.next/server/app/index.rsc +1 -1
- package/mcp-server/.next/server/app/logs/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/mcp/route.js +2 -2
- package/mcp-server/.next/server/app/mcp/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/video/[session]/page.js.nft.json +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__05e38acd._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__94037b23._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__ae49815f._.js +50 -12
- package/mcp-server/.next/server/chunks/[root-of-the-server]__ae49815f._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__cc74dbef._.js.map +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__dc0b0022._.js +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__dc0b0022._.js.map +1 -1
- package/mcp-server/.next/server/chunks/ssr/mcp-server_app_page_tsx_9fc46577._.js.map +1 -1
- package/mcp-server/.next/server/server-reference-manifest.js +1 -1
- package/mcp-server/.next/server/server-reference-manifest.json +1 -1
- package/mcp-server/app/api/orchestrator/route.ts +1 -1
- package/mcp-server/app/mcp/client-manager.ts +1 -1
- package/mcp-server/app/mcp/route.ts +13 -1
- package/mcp-server/app/mcp/tools.ts +332 -5
- package/mcp-server/app/page.tsx +0 -1
- package/package.json +1 -1
- /package/mcp-server/.next/static/{4QTQwT0vriZN0rBeHTIWl → eVL_05d0pOH_qw2twMoct}/_buildManifest.js +0 -0
- /package/mcp-server/.next/static/{4QTQwT0vriZN0rBeHTIWl → eVL_05d0pOH_qw2twMoct}/_clientMiddlewareManifest.json +0 -0
- /package/mcp-server/.next/static/{4QTQwT0vriZN0rBeHTIWl → eVL_05d0pOH_qw2twMoct}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["turbopack:///[project]/mcp-server/app/page.tsx","turbopack:///[project]/mcp-server/components/mcp-icons.tsx"],"sourcesContent":["\"use client\"\n\nimport Link from \"next/link\"\nimport { useEffect, useState } from \"react\"\nimport { DarkModeToggle } from \"@/components/dark-mode-toggle\"\nimport { ChromeIcon, NextJsIcon } from \"@/components/mcp-icons\"\nimport { useDarkMode } from \"@/hooks/use-dark-mode\"\n\ninterface MCPTool {\n name: string\n description: string\n category: string\n parameters: Array<{\n name: string\n type: string\n optional?: boolean\n description: string\n }>\n}\n\ninterface ToolsResponse {\n tools: MCPTool[]\n endpoint: string\n totalTools: number\n categories: string[]\n}\n\ninterface OrchestratorResponse {\n orchestratorEnabled: boolean\n connectedMCPs: string[]\n totalConnections: number\n mcpDetails: Array<{\n name: string\n connected: boolean\n toolCount: number\n tools: string[]\n projects: string[]\n }>\n totalProjects: number\n projects: string[]\n message: string\n}\n\n// Format tool descriptions by parsing markdown-style sections\nfunction formatToolDescription(description: string) {\n const slugify = (value: string) =>\n value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\")\n\n // Split by double newline to get sections\n const sections = description.split(\"\\n\\n\").filter((section) => section.trim())\n const keyCounts = new Map<string, number>()\n\n const getUniqueKey = (base: string) => {\n const count = keyCounts.get(base) ?? 0\n keyCounts.set(base, count + 1)\n return count === 0 ? base : `${base}-${count}`\n }\n\n return sections.map((rawSection, _idx) => {\n const normalizedKey = getUniqueKey(slugify(rawSection) || \"section\")\n let section = rawSection\n\n // Remove markdown formatting\n section = section.replace(/\\*\\*/g, \"\").trim()\n\n // Remove excessive emojis\n section = section.replace(/(\\u{1F300}-\\u{1F9FF}|\\u{2600}-\\u{26FF}|\\u{1F900}-\\u{1F9FF})+/gu, (match) => {\n return match.charAt(0)\n })\n\n // Handle different section types\n if (section.includes(\":\")) {\n // This is a header with content\n const [header, ...contentParts] = section.split(\":\")\n const cleanHeader = header.trim()\n const content = contentParts.join(\":\").trim()\n\n // Check if content has bullet points\n if (content.includes(\"•\")) {\n const items = content.split(\"•\").filter((item) => item.trim())\n const sectionKey = `${normalizedKey}-bullets`\n return (\n <div key={sectionKey}>\n <h5 className=\"font-semibold mb-2\">{cleanHeader}</h5>\n <ul className=\"space-y-1 ml-4\">\n {items.map((item) => {\n const itemKey = getUniqueKey(`${sectionKey}-item-${slugify(item).slice(0, 40) || \"bullet\"}`)\n return (\n <li key={itemKey} className=\"flex items-start\">\n <span className=\"text-muted-foreground mr-2\">•</span>\n <span className=\"text-muted-foreground text-sm\">{item.trim()}</span>\n </li>\n )\n })}\n </ul>\n </div>\n )\n }\n\n return (\n <div key={`${normalizedKey}-content`}>\n <h5 className=\"font-semibold mb-1\">{cleanHeader}</h5>\n <p className=\"text-muted-foreground text-sm ml-4\">{content}</p>\n </div>\n )\n }\n\n // Handle numbered lists (like workflow steps)\n if (section.match(/^\\d+[\\ud83c-\\ud83e][\\udc00-\\udfff]|^\\d+\\./m)) {\n const items = section.split(/\\n/).filter((item) => item.trim())\n return (\n <ol className=\"space-y-1 ml-4\" key={`${normalizedKey}-steps`}>\n {items.map((item, itemIdx) => {\n const cleanItem = item\n .replace(/^\\d+[\\ud83c-\\ud83e][\\udc00-\\udfff]\\s*/, \"\")\n .replace(/^\\d+\\.\\s*/, \"\")\n .trim()\n return (\n <li\n key={getUniqueKey(`${normalizedKey}-step-${slugify(cleanItem).slice(0, 40) || \"step\"}`)}\n className=\"text-muted-foreground text-sm\"\n >\n {itemIdx + 1}. {cleanItem}\n </li>\n )\n })}\n </ol>\n )\n }\n\n // Default paragraph\n return (\n <p key={`${normalizedKey}-paragraph`} className=\"text-muted-foreground text-sm leading-relaxed\">\n {section}\n </p>\n )\n })\n}\n\nexport default function HomePage() {\n const [tools, setTools] = useState<ToolsResponse | null>(null)\n const [orchestrator, setOrchestrator] = useState<OrchestratorResponse | null>(null)\n const [loading, setLoading] = useState(true)\n const [darkMode, setDarkMode] = useDarkMode()\n\n useEffect(() => {\n // Fetch both tools and orchestrator status in parallel\n Promise.all([fetch(\"/api/tools\"), fetch(\"/api/orchestrator\")])\n .then(([toolsRes, orchRes]) => Promise.all([toolsRes.json(), orchRes.json()]))\n .then(([toolsData, orchData]) => {\n setTools(toolsData)\n setOrchestrator(orchData)\n setLoading(false)\n })\n .catch(() => {\n setLoading(false)\n })\n }, [])\n\n return (\n <div className=\"min-h-screen bg-background text-foreground\">\n {/* Header */}\n <header className=\"bg-muted/30 border-b border-border\">\n <div className=\"max-w-7xl mx-auto px-6 py-8\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-4 mb-3\">\n <div className=\"w-12 h-12 bg-foreground rounded flex items-center justify-center\">\n <span className=\"text-background font-mono font-bold\">d3k</span>\n </div>\n <div>\n <h1 className=\"text-3xl font-bold\">dev3000 MCP Server</h1>\n <div className=\"flex items-center gap-3 mt-2\">\n <span className=\"inline-flex items-center gap-2 text-sm text-green-600 font-medium\">\n <span className=\"w-2 h-2 bg-green-500 rounded-full\"></span>\n Server Running\n </span>\n <span className=\"text-muted-foreground\">•</span>\n <span className=\"text-sm text-muted-foreground\">Port {process.env.PORT || \"3684\"}</span>\n </div>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-4\">\n <a\n href=\"https://github.com/vercel-labs/dev3000#setup\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 px-5 py-3 border border-border text-foreground text-sm font-medium rounded hover:bg-accent hover:text-accent-foreground transition-colors\"\n >\n 📖 Setup Guide\n </a>\n <DarkModeToggle darkMode={darkMode} setDarkMode={setDarkMode} />\n </div>\n </div>\n </div>\n </header>\n\n {/* Main Content - no sidebar needed with only 2 tools */}\n <main className=\"max-w-7xl mx-auto px-6 py-8\">\n {/* MCP Connections Status */}\n {!loading && orchestrator && (\n <section className=\"mb-16\">\n <div className=\"bg-accent/10 border border-accent/20 rounded p-8\">\n <h2 className=\"text-xl font-semibold mb-4\">🔌 MCP Connections</h2>\n <p className=\"text-sm text-muted-foreground mb-4\">{orchestrator.message}</p>\n\n {orchestrator.totalConnections > 0 ? (\n <>\n <div className=\"flex flex-wrap gap-3 mb-4\">\n {orchestrator.mcpDetails.map((mcp) => {\n const Icon =\n mcp.name === \"chrome-devtools\" ? ChromeIcon : mcp.name === \"nextjs-dev\" ? NextJsIcon : null\n return (\n <div\n key={mcp.name}\n className=\"inline-flex items-center gap-2 bg-background/50 border border-border rounded px-3 py-2\"\n >\n {Icon && <Icon className=\"shrink-0\" />}\n <span className=\"font-semibold font-mono text-sm\">{mcp.name}</span>\n <span className=\"w-2 h-2 bg-green-500 rounded-full\"></span>\n </div>\n )\n })}\n </div>\n {orchestrator.totalProjects > 0 && (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"font-medium\">Active projects:</span>{\" \"}\n {orchestrator.projects.map((project, idx) => (\n <span key={project}>\n <code className=\"text-foreground bg-background/50 px-1.5 py-0.5 rounded\">{project}</code>\n {idx < orchestrator.projects.length - 1 && \", \"}\n </span>\n ))}\n </div>\n )}\n </>\n ) : (\n <div className=\"text-sm text-muted-foreground bg-background/50 border border-border rounded p-4\">\n <p className=\"mb-2\">⏳ Waiting for downstream MCPs to become available...</p>\n <p className=\"text-xs\">\n dev3000 will automatically connect to <code className=\"text-foreground\">chrome-devtools</code> and{\" \"}\n <code className=\"text-foreground\">nextjs-dev</code> MCPs when Chrome and your dev server start.\n </p>\n </div>\n )}\n </div>\n </section>\n )}\n\n {/* Tools Documentation */}\n <section className=\"bg-accent/10 border border-accent/20 rounded p-8\">\n <h2 className=\"text-xl font-semibold mb-4\">🛠️ dev3000 Tools</h2>\n\n {loading ? (\n <div className=\"text-center py-16\">\n <div className=\"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary\"></div>\n <p className=\"mt-6 text-muted-foreground\">Loading tool documentation...</p>\n </div>\n ) : tools ? (\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {tools.tools.map((tool) => (\n <div\n key={tool.name}\n id={tool.name}\n className=\"bg-background/50 border border-border rounded-lg p-6 hover:border-muted-foreground/50 transition-colors\"\n >\n <div className=\"mb-4\">\n <h4 className=\"text-xl font-semibold font-mono mb-3\">{tool.name}</h4>\n <div className=\"text-muted-foreground space-y-3\">{formatToolDescription(tool.description)}</div>\n </div>\n {tool.parameters.length > 0 && (\n <div>\n <h5 className=\"text-sm font-semibold mb-3\">Parameters:</h5>\n <div className=\"space-y-2\">\n {tool.parameters.map((param) => (\n <div key={param.name} className=\"text-sm\">\n <div className=\"flex items-start gap-2\">\n <span className=\"font-mono text-primary font-medium\">{param.name}</span>\n <span className=\"text-muted-foreground text-xs\">\n {param.optional ? \"(optional)\" : \"(required)\"}\n </span>\n <span className=\"text-muted-foreground/70 text-xs\">- {param.type}</span>\n </div>\n {param.description && (\n <div className=\"text-muted-foreground ml-1 mt-1 text-sm\">{param.description}</div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-16\">\n <p className=\"text-destructive mb-6\">Failed to load tool documentation</p>\n <button\n onClick={() => window.location.reload()}\n className=\"px-6 py-3 bg-primary text-primary-foreground text-sm rounded hover:bg-primary/90 transition-colors\"\n type=\"button\"\n >\n Retry\n </button>\n </div>\n )}\n </section>\n\n {/* Magic Workflow */}\n <section className=\"mt-20 bg-gradient-to-r from-primary/10 to-secondary/10 border border-border rounded-lg p-10\">\n <h2 className=\"text-2xl font-semibold mb-6 flex items-center gap-3\">🪄 The Magic Workflow</h2>\n <div className=\"grid md:grid-cols-3 gap-8\">\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-primary/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-primary font-bold text-2xl\">1</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Finds Issues</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n fix_my_app automatically detects all types of errors and problems in your app\n </p>\n </div>\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-accent/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-accent-foreground font-bold text-2xl\">2</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Fixes Code</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n AI analyzes errors and edits your code files to resolve issues\n </p>\n </div>\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-green-500/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-green-600 dark:text-green-400 font-bold text-2xl\">3</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Verifies Fixes</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n execute_browser_action tests the fixes in real-time with screenshots\n </p>\n </div>\n </div>\n </section>\n </main>\n\n {/* Footer */}\n <footer className=\"border-t border-border mt-20\">\n <div className=\"max-w-7xl mx-auto px-6 py-8\">\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <div>\n <span className=\"font-semibold\">dev3000 MCP Server</span> - AI-powered development monitoring\n </div>\n <div className=\"flex items-center gap-8\">\n <a\n href=\"https://github.com/vercel-labs/dev3000\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-foreground transition-colors\"\n >\n GitHub\n </a>\n <a\n href=\"https://dev3000.ai\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-foreground transition-colors\"\n >\n Homepage\n </a>\n </div>\n </div>\n </div>\n </footer>\n </div>\n )\n}\n","import { useId } from \"react\"\n\nexport function NextJsIcon({ className }: { className?: string }) {\n const lightMaskId = useId()\n const lightPaint0Id = useId()\n const lightPaint1Id = useId()\n const darkMaskId = useId()\n const darkPaint0Id = useId()\n const darkPaint1Id = useId()\n\n return (\n <>\n {/* Light mode */}\n <svg\n aria-label=\"Next.js logomark\"\n className={`${className} block dark:hidden`}\n height=\"16\"\n role=\"img\"\n viewBox=\"0 0 180 180\"\n width=\"16\"\n >\n <mask\n height=\"180\"\n id={lightMaskId}\n maskUnits=\"userSpaceOnUse\"\n width=\"180\"\n x=\"0\"\n y=\"0\"\n style={{ maskType: \"alpha\" }}\n >\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n </mask>\n <g mask={`url(#${lightMaskId})`}>\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n <path\n d=\"M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z\"\n fill={`url(#${lightPaint0Id})`}\n />\n <rect fill={`url(#${lightPaint1Id})`} height=\"72\" width=\"12\" x=\"115\" y=\"54\" />\n </g>\n <defs>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={lightPaint0Id} x1=\"109\" x2=\"144.5\" y1=\"116.5\" y2=\"160.5\">\n <stop stopColor=\"white\" />\n <stop offset=\"1\" stopColor=\"white\" stopOpacity=\"0\" />\n </linearGradient>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={lightPaint1Id} x1=\"121\" x2=\"120.799\" y1=\"54\" y2=\"106.875\">\n <stop stopColor=\"white\" />\n <stop offset=\"1\" stopColor=\"white\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n </svg>\n\n {/* Dark mode */}\n <svg\n aria-label=\"Next.js logomark\"\n className={`${className} hidden dark:block`}\n height=\"16\"\n role=\"img\"\n viewBox=\"0 0 180 180\"\n width=\"16\"\n >\n <mask\n height=\"180\"\n id={darkMaskId}\n maskUnits=\"userSpaceOnUse\"\n width=\"180\"\n x=\"0\"\n y=\"0\"\n style={{ maskType: \"alpha\" }}\n >\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n </mask>\n <g mask={`url(#${darkMaskId})`}>\n <circle cx=\"90\" cy=\"90\" fill=\"white\" r=\"90\" />\n <path\n d=\"M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z\"\n fill={`url(#${darkPaint0Id})`}\n />\n <rect fill={`url(#${darkPaint1Id})`} height=\"72\" width=\"12\" x=\"115\" y=\"54\" />\n </g>\n <defs>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={darkPaint0Id} x1=\"109\" x2=\"144.5\" y1=\"116.5\" y2=\"160.5\">\n <stop stopColor=\"black\" />\n <stop offset=\"1\" stopColor=\"black\" stopOpacity=\"0\" />\n </linearGradient>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={darkPaint1Id} x1=\"121\" x2=\"120.799\" y1=\"54\" y2=\"106.875\">\n <stop stopColor=\"black\" />\n <stop offset=\"1\" stopColor=\"black\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n </svg>\n </>\n )\n}\n\nexport function ChromeIcon({ className }: { className?: string }) {\n const gradientAId = useId()\n const gradientBId = useId()\n const gradientCId = useId()\n\n return (\n <svg className={className} viewBox=\"0 0 48 48\" height=\"16\" width=\"16\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <linearGradient id={gradientAId} x1=\"3.2173\" y1=\"15\" x2=\"44.7812\" y2=\"15\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0\" stopColor=\"#d93025\" />\n <stop offset=\"1\" stopColor=\"#ea4335\" />\n </linearGradient>\n <linearGradient\n id={gradientBId}\n x1=\"20.7219\"\n y1=\"47.6791\"\n x2=\"41.5039\"\n y2=\"11.6837\"\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop offset=\"0\" stopColor=\"#fcc934\" />\n <stop offset=\"1\" stopColor=\"#fbbc04\" />\n </linearGradient>\n <linearGradient\n id={gradientCId}\n x1=\"26.5981\"\n y1=\"46.5015\"\n x2=\"5.8161\"\n y2=\"10.506\"\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop offset=\"0\" stopColor=\"#1e8e3e\" />\n <stop offset=\"1\" stopColor=\"#34a853\" />\n </linearGradient>\n </defs>\n <circle cx=\"24\" cy=\"23.9947\" r=\"12\" style={{ fill: \"#fff\" }} />\n <path\n d=\"M3.2154,36A24,24,0,1,0,12,3.2154,24,24,0,0,0,3.2154,36ZM34.3923,18A12,12,0,1,1,18,13.6077,12,12,0,0,1,34.3923,18Z\"\n style={{ fill: \"none\" }}\n />\n <path\n d=\"M24,12H44.7812a23.9939,23.9939,0,0,0-41.5639.0029L13.6079,30l.0093-.0024A11.9852,11.9852,0,0,1,24,12Z\"\n style={{ fill: `url(#${gradientAId})` }}\n />\n <circle cx=\"24\" cy=\"24\" r=\"9.5\" style={{ fill: \"#1a73e8\" }} />\n <path\n d=\"M34.3913,30.0029,24.0007,48A23.994,23.994,0,0,0,44.78,12.0031H23.9989l-.0025.0093A11.985,11.985,0,0,1,34.3913,30.0029Z\"\n style={{ fill: `url(#${gradientBId})` }}\n />\n <path\n d=\"M13.6086,30.0031,3.218,12.006A23.994,23.994,0,0,0,24.0025,48L34.3931,30.0029l-.0067-.0068a11.9852,11.9852,0,0,1-20.7778.007Z\"\n style={{ fill: `url(#${gradientCId})` }}\n />\n </svg>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["turbopack:///[project]/mcp-server/app/page.tsx","turbopack:///[project]/mcp-server/components/mcp-icons.tsx"],"sourcesContent":["\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport { DarkModeToggle } from \"@/components/dark-mode-toggle\"\nimport { ChromeIcon, NextJsIcon } from \"@/components/mcp-icons\"\nimport { useDarkMode } from \"@/hooks/use-dark-mode\"\n\ninterface MCPTool {\n name: string\n description: string\n category: string\n parameters: Array<{\n name: string\n type: string\n optional?: boolean\n description: string\n }>\n}\n\ninterface ToolsResponse {\n tools: MCPTool[]\n endpoint: string\n totalTools: number\n categories: string[]\n}\n\ninterface OrchestratorResponse {\n orchestratorEnabled: boolean\n connectedMCPs: string[]\n totalConnections: number\n mcpDetails: Array<{\n name: string\n connected: boolean\n toolCount: number\n tools: string[]\n projects: string[]\n }>\n totalProjects: number\n projects: string[]\n message: string\n}\n\n// Format tool descriptions by parsing markdown-style sections\nfunction formatToolDescription(description: string) {\n const slugify = (value: string) =>\n value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\")\n\n // Split by double newline to get sections\n const sections = description.split(\"\\n\\n\").filter((section) => section.trim())\n const keyCounts = new Map<string, number>()\n\n const getUniqueKey = (base: string) => {\n const count = keyCounts.get(base) ?? 0\n keyCounts.set(base, count + 1)\n return count === 0 ? base : `${base}-${count}`\n }\n\n return sections.map((rawSection, _idx) => {\n const normalizedKey = getUniqueKey(slugify(rawSection) || \"section\")\n let section = rawSection\n\n // Remove markdown formatting\n section = section.replace(/\\*\\*/g, \"\").trim()\n\n // Remove excessive emojis\n section = section.replace(/(\\u{1F300}-\\u{1F9FF}|\\u{2600}-\\u{26FF}|\\u{1F900}-\\u{1F9FF})+/gu, (match) => {\n return match.charAt(0)\n })\n\n // Handle different section types\n if (section.includes(\":\")) {\n // This is a header with content\n const [header, ...contentParts] = section.split(\":\")\n const cleanHeader = header.trim()\n const content = contentParts.join(\":\").trim()\n\n // Check if content has bullet points\n if (content.includes(\"•\")) {\n const items = content.split(\"•\").filter((item) => item.trim())\n const sectionKey = `${normalizedKey}-bullets`\n return (\n <div key={sectionKey}>\n <h5 className=\"font-semibold mb-2\">{cleanHeader}</h5>\n <ul className=\"space-y-1 ml-4\">\n {items.map((item) => {\n const itemKey = getUniqueKey(`${sectionKey}-item-${slugify(item).slice(0, 40) || \"bullet\"}`)\n return (\n <li key={itemKey} className=\"flex items-start\">\n <span className=\"text-muted-foreground mr-2\">•</span>\n <span className=\"text-muted-foreground text-sm\">{item.trim()}</span>\n </li>\n )\n })}\n </ul>\n </div>\n )\n }\n\n return (\n <div key={`${normalizedKey}-content`}>\n <h5 className=\"font-semibold mb-1\">{cleanHeader}</h5>\n <p className=\"text-muted-foreground text-sm ml-4\">{content}</p>\n </div>\n )\n }\n\n // Handle numbered lists (like workflow steps)\n if (section.match(/^\\d+[\\ud83c-\\ud83e][\\udc00-\\udfff]|^\\d+\\./m)) {\n const items = section.split(/\\n/).filter((item) => item.trim())\n return (\n <ol className=\"space-y-1 ml-4\" key={`${normalizedKey}-steps`}>\n {items.map((item, itemIdx) => {\n const cleanItem = item\n .replace(/^\\d+[\\ud83c-\\ud83e][\\udc00-\\udfff]\\s*/, \"\")\n .replace(/^\\d+\\.\\s*/, \"\")\n .trim()\n return (\n <li\n key={getUniqueKey(`${normalizedKey}-step-${slugify(cleanItem).slice(0, 40) || \"step\"}`)}\n className=\"text-muted-foreground text-sm\"\n >\n {itemIdx + 1}. {cleanItem}\n </li>\n )\n })}\n </ol>\n )\n }\n\n // Default paragraph\n return (\n <p key={`${normalizedKey}-paragraph`} className=\"text-muted-foreground text-sm leading-relaxed\">\n {section}\n </p>\n )\n })\n}\n\nexport default function HomePage() {\n const [tools, setTools] = useState<ToolsResponse | null>(null)\n const [orchestrator, setOrchestrator] = useState<OrchestratorResponse | null>(null)\n const [loading, setLoading] = useState(true)\n const [darkMode, setDarkMode] = useDarkMode()\n\n useEffect(() => {\n // Fetch both tools and orchestrator status in parallel\n Promise.all([fetch(\"/api/tools\"), fetch(\"/api/orchestrator\")])\n .then(([toolsRes, orchRes]) => Promise.all([toolsRes.json(), orchRes.json()]))\n .then(([toolsData, orchData]) => {\n setTools(toolsData)\n setOrchestrator(orchData)\n setLoading(false)\n })\n .catch(() => {\n setLoading(false)\n })\n }, [])\n\n return (\n <div className=\"min-h-screen bg-background text-foreground\">\n {/* Header */}\n <header className=\"bg-muted/30 border-b border-border\">\n <div className=\"max-w-7xl mx-auto px-6 py-8\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-4 mb-3\">\n <div className=\"w-12 h-12 bg-foreground rounded flex items-center justify-center\">\n <span className=\"text-background font-mono font-bold\">d3k</span>\n </div>\n <div>\n <h1 className=\"text-3xl font-bold\">dev3000 MCP Server</h1>\n <div className=\"flex items-center gap-3 mt-2\">\n <span className=\"inline-flex items-center gap-2 text-sm text-green-600 font-medium\">\n <span className=\"w-2 h-2 bg-green-500 rounded-full\"></span>\n Server Running\n </span>\n <span className=\"text-muted-foreground\">•</span>\n <span className=\"text-sm text-muted-foreground\">Port {process.env.PORT || \"3684\"}</span>\n </div>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-4\">\n <a\n href=\"https://github.com/vercel-labs/dev3000#setup\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 px-5 py-3 border border-border text-foreground text-sm font-medium rounded hover:bg-accent hover:text-accent-foreground transition-colors\"\n >\n 📖 Setup Guide\n </a>\n <DarkModeToggle darkMode={darkMode} setDarkMode={setDarkMode} />\n </div>\n </div>\n </div>\n </header>\n\n {/* Main Content - no sidebar needed with only 2 tools */}\n <main className=\"max-w-7xl mx-auto px-6 py-8\">\n {/* MCP Connections Status */}\n {!loading && orchestrator && (\n <section className=\"mb-16\">\n <div className=\"bg-accent/10 border border-accent/20 rounded p-8\">\n <h2 className=\"text-xl font-semibold mb-4\">🔌 MCP Connections</h2>\n <p className=\"text-sm text-muted-foreground mb-4\">{orchestrator.message}</p>\n\n {orchestrator.totalConnections > 0 ? (\n <>\n <div className=\"flex flex-wrap gap-3 mb-4\">\n {orchestrator.mcpDetails.map((mcp) => {\n const Icon =\n mcp.name === \"chrome-devtools\" ? ChromeIcon : mcp.name === \"nextjs-dev\" ? NextJsIcon : null\n return (\n <div\n key={mcp.name}\n className=\"inline-flex items-center gap-2 bg-background/50 border border-border rounded px-3 py-2\"\n >\n {Icon && <Icon className=\"shrink-0\" />}\n <span className=\"font-semibold font-mono text-sm\">{mcp.name}</span>\n <span className=\"w-2 h-2 bg-green-500 rounded-full\"></span>\n </div>\n )\n })}\n </div>\n {orchestrator.totalProjects > 0 && (\n <div className=\"text-sm text-muted-foreground\">\n <span className=\"font-medium\">Active projects:</span>{\" \"}\n {orchestrator.projects.map((project, idx) => (\n <span key={project}>\n <code className=\"text-foreground bg-background/50 px-1.5 py-0.5 rounded\">{project}</code>\n {idx < orchestrator.projects.length - 1 && \", \"}\n </span>\n ))}\n </div>\n )}\n </>\n ) : (\n <div className=\"text-sm text-muted-foreground bg-background/50 border border-border rounded p-4\">\n <p className=\"mb-2\">⏳ Waiting for downstream MCPs to become available...</p>\n <p className=\"text-xs\">\n dev3000 will automatically connect to <code className=\"text-foreground\">chrome-devtools</code> and{\" \"}\n <code className=\"text-foreground\">nextjs-dev</code> MCPs when Chrome and your dev server start.\n </p>\n </div>\n )}\n </div>\n </section>\n )}\n\n {/* Tools Documentation */}\n <section className=\"bg-accent/10 border border-accent/20 rounded p-8\">\n <h2 className=\"text-xl font-semibold mb-4\">🛠️ dev3000 Tools</h2>\n\n {loading ? (\n <div className=\"text-center py-16\">\n <div className=\"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary\"></div>\n <p className=\"mt-6 text-muted-foreground\">Loading tool documentation...</p>\n </div>\n ) : tools ? (\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {tools.tools.map((tool) => (\n <div\n key={tool.name}\n id={tool.name}\n className=\"bg-background/50 border border-border rounded-lg p-6 hover:border-muted-foreground/50 transition-colors\"\n >\n <div className=\"mb-4\">\n <h4 className=\"text-xl font-semibold font-mono mb-3\">{tool.name}</h4>\n <div className=\"text-muted-foreground space-y-3\">{formatToolDescription(tool.description)}</div>\n </div>\n {tool.parameters.length > 0 && (\n <div>\n <h5 className=\"text-sm font-semibold mb-3\">Parameters:</h5>\n <div className=\"space-y-2\">\n {tool.parameters.map((param) => (\n <div key={param.name} className=\"text-sm\">\n <div className=\"flex items-start gap-2\">\n <span className=\"font-mono text-primary font-medium\">{param.name}</span>\n <span className=\"text-muted-foreground text-xs\">\n {param.optional ? \"(optional)\" : \"(required)\"}\n </span>\n <span className=\"text-muted-foreground/70 text-xs\">- {param.type}</span>\n </div>\n {param.description && (\n <div className=\"text-muted-foreground ml-1 mt-1 text-sm\">{param.description}</div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-16\">\n <p className=\"text-destructive mb-6\">Failed to load tool documentation</p>\n <button\n onClick={() => window.location.reload()}\n className=\"px-6 py-3 bg-primary text-primary-foreground text-sm rounded hover:bg-primary/90 transition-colors\"\n type=\"button\"\n >\n Retry\n </button>\n </div>\n )}\n </section>\n\n {/* Magic Workflow */}\n <section className=\"mt-20 bg-gradient-to-r from-primary/10 to-secondary/10 border border-border rounded-lg p-10\">\n <h2 className=\"text-2xl font-semibold mb-6 flex items-center gap-3\">🪄 The Magic Workflow</h2>\n <div className=\"grid md:grid-cols-3 gap-8\">\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-primary/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-primary font-bold text-2xl\">1</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Finds Issues</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n fix_my_app automatically detects all types of errors and problems in your app\n </p>\n </div>\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-accent/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-accent-foreground font-bold text-2xl\">2</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Fixes Code</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n AI analyzes errors and edits your code files to resolve issues\n </p>\n </div>\n <div className=\"text-center\">\n <div className=\"w-16 h-16 bg-green-500/20 rounded-full flex items-center justify-center mx-auto mb-4 shadow-md\">\n <span className=\"text-green-600 dark:text-green-400 font-bold text-2xl\">3</span>\n </div>\n <h3 className=\"font-semibold mb-3 text-lg\">AI Verifies Fixes</h3>\n <p className=\"text-muted-foreground leading-relaxed\">\n execute_browser_action tests the fixes in real-time with screenshots\n </p>\n </div>\n </div>\n </section>\n </main>\n\n {/* Footer */}\n <footer className=\"border-t border-border mt-20\">\n <div className=\"max-w-7xl mx-auto px-6 py-8\">\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <div>\n <span className=\"font-semibold\">dev3000 MCP Server</span> - AI-powered development monitoring\n </div>\n <div className=\"flex items-center gap-8\">\n <a\n href=\"https://github.com/vercel-labs/dev3000\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-foreground transition-colors\"\n >\n GitHub\n </a>\n <a\n href=\"https://dev3000.ai\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hover:text-foreground transition-colors\"\n >\n Homepage\n </a>\n </div>\n </div>\n </div>\n </footer>\n </div>\n )\n}\n","import { useId } from \"react\"\n\nexport function NextJsIcon({ className }: { className?: string }) {\n const lightMaskId = useId()\n const lightPaint0Id = useId()\n const lightPaint1Id = useId()\n const darkMaskId = useId()\n const darkPaint0Id = useId()\n const darkPaint1Id = useId()\n\n return (\n <>\n {/* Light mode */}\n <svg\n aria-label=\"Next.js logomark\"\n className={`${className} block dark:hidden`}\n height=\"16\"\n role=\"img\"\n viewBox=\"0 0 180 180\"\n width=\"16\"\n >\n <mask\n height=\"180\"\n id={lightMaskId}\n maskUnits=\"userSpaceOnUse\"\n width=\"180\"\n x=\"0\"\n y=\"0\"\n style={{ maskType: \"alpha\" }}\n >\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n </mask>\n <g mask={`url(#${lightMaskId})`}>\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n <path\n d=\"M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z\"\n fill={`url(#${lightPaint0Id})`}\n />\n <rect fill={`url(#${lightPaint1Id})`} height=\"72\" width=\"12\" x=\"115\" y=\"54\" />\n </g>\n <defs>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={lightPaint0Id} x1=\"109\" x2=\"144.5\" y1=\"116.5\" y2=\"160.5\">\n <stop stopColor=\"white\" />\n <stop offset=\"1\" stopColor=\"white\" stopOpacity=\"0\" />\n </linearGradient>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={lightPaint1Id} x1=\"121\" x2=\"120.799\" y1=\"54\" y2=\"106.875\">\n <stop stopColor=\"white\" />\n <stop offset=\"1\" stopColor=\"white\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n </svg>\n\n {/* Dark mode */}\n <svg\n aria-label=\"Next.js logomark\"\n className={`${className} hidden dark:block`}\n height=\"16\"\n role=\"img\"\n viewBox=\"0 0 180 180\"\n width=\"16\"\n >\n <mask\n height=\"180\"\n id={darkMaskId}\n maskUnits=\"userSpaceOnUse\"\n width=\"180\"\n x=\"0\"\n y=\"0\"\n style={{ maskType: \"alpha\" }}\n >\n <circle cx=\"90\" cy=\"90\" fill=\"black\" r=\"90\" />\n </mask>\n <g mask={`url(#${darkMaskId})`}>\n <circle cx=\"90\" cy=\"90\" fill=\"white\" r=\"90\" />\n <path\n d=\"M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z\"\n fill={`url(#${darkPaint0Id})`}\n />\n <rect fill={`url(#${darkPaint1Id})`} height=\"72\" width=\"12\" x=\"115\" y=\"54\" />\n </g>\n <defs>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={darkPaint0Id} x1=\"109\" x2=\"144.5\" y1=\"116.5\" y2=\"160.5\">\n <stop stopColor=\"black\" />\n <stop offset=\"1\" stopColor=\"black\" stopOpacity=\"0\" />\n </linearGradient>\n <linearGradient gradientUnits=\"userSpaceOnUse\" id={darkPaint1Id} x1=\"121\" x2=\"120.799\" y1=\"54\" y2=\"106.875\">\n <stop stopColor=\"black\" />\n <stop offset=\"1\" stopColor=\"black\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n </svg>\n </>\n )\n}\n\nexport function ChromeIcon({ className }: { className?: string }) {\n const gradientAId = useId()\n const gradientBId = useId()\n const gradientCId = useId()\n\n return (\n <svg className={className} viewBox=\"0 0 48 48\" height=\"16\" width=\"16\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <linearGradient id={gradientAId} x1=\"3.2173\" y1=\"15\" x2=\"44.7812\" y2=\"15\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0\" stopColor=\"#d93025\" />\n <stop offset=\"1\" stopColor=\"#ea4335\" />\n </linearGradient>\n <linearGradient\n id={gradientBId}\n x1=\"20.7219\"\n y1=\"47.6791\"\n x2=\"41.5039\"\n y2=\"11.6837\"\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop offset=\"0\" stopColor=\"#fcc934\" />\n <stop offset=\"1\" stopColor=\"#fbbc04\" />\n </linearGradient>\n <linearGradient\n id={gradientCId}\n x1=\"26.5981\"\n y1=\"46.5015\"\n x2=\"5.8161\"\n y2=\"10.506\"\n gradientUnits=\"userSpaceOnUse\"\n >\n <stop offset=\"0\" stopColor=\"#1e8e3e\" />\n <stop offset=\"1\" stopColor=\"#34a853\" />\n </linearGradient>\n </defs>\n <circle cx=\"24\" cy=\"23.9947\" r=\"12\" style={{ fill: \"#fff\" }} />\n <path\n d=\"M3.2154,36A24,24,0,1,0,12,3.2154,24,24,0,0,0,3.2154,36ZM34.3923,18A12,12,0,1,1,18,13.6077,12,12,0,0,1,34.3923,18Z\"\n style={{ fill: \"none\" }}\n />\n <path\n d=\"M24,12H44.7812a23.9939,23.9939,0,0,0-41.5639.0029L13.6079,30l.0093-.0024A11.9852,11.9852,0,0,1,24,12Z\"\n style={{ fill: `url(#${gradientAId})` }}\n />\n <circle cx=\"24\" cy=\"24\" r=\"9.5\" style={{ fill: \"#1a73e8\" }} />\n <path\n d=\"M34.3913,30.0029,24.0007,48A23.994,23.994,0,0,0,44.78,12.0031H23.9989l-.0025.0093A11.985,11.985,0,0,1,34.3913,30.0029Z\"\n style={{ fill: `url(#${gradientBId})` }}\n />\n <path\n d=\"M13.6086,30.0031,3.218,12.006A23.994,23.994,0,0,0,24.0025,48L34.3931,30.0029l-.0067-.0068a11.9852,11.9852,0,0,1-20.7778.007Z\"\n style={{ fill: `url(#${gradientCId})` }}\n />\n </svg>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"+
|
|
1
|
+
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"mkpbqeA8hbQBwumcGof8mtazY/m9j2lVb+4otV6eSo0=\"\n}"
|
|
@@ -6,7 +6,7 @@ import { getMCPClientManager } from "@/app/mcp/client-manager"
|
|
|
6
6
|
|
|
7
7
|
export const dynamic = "force-dynamic"
|
|
8
8
|
|
|
9
|
-
export async function GET(
|
|
9
|
+
export async function GET(_request: Request) {
|
|
10
10
|
const clientManager = getMCPClientManager()
|
|
11
11
|
const connectedMCPs = clientManager.getConnectedMCPs()
|
|
12
12
|
const allTools = clientManager.getAllTools()
|
|
@@ -134,7 +134,7 @@ export class MCPClientManager {
|
|
|
134
134
|
this.tools.set(config.name, [])
|
|
135
135
|
console.log(`[MCP Orchestrator] No tools discovered from ${config.name} (will retry on first use)`)
|
|
136
136
|
}
|
|
137
|
-
} catch (
|
|
137
|
+
} catch (_error) {
|
|
138
138
|
// Tool discovery failed but connection succeeded - tools will be discovered on first use
|
|
139
139
|
this.tools.set(config.name, [])
|
|
140
140
|
console.log(`[MCP Orchestrator] Tool discovery deferred for ${config.name} (will discover on first tool call)`)
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path"
|
|
|
4
4
|
import { createMcpHandler } from "mcp-handler"
|
|
5
5
|
import { z } from "zod"
|
|
6
6
|
import { getMCPClientManager } from "./client-manager"
|
|
7
|
-
import { executeBrowserAction, findComponentSource, fixMyApp, TOOL_DESCRIPTIONS } from "./tools"
|
|
7
|
+
import { executeBrowserAction, findComponentSource, fixMyApp, restartDevServer, TOOL_DESCRIPTIONS } from "./tools"
|
|
8
8
|
|
|
9
9
|
// Detect available package runner (npx, pnpm dlx, or fail)
|
|
10
10
|
const getPackageRunner = (): { command: string; args: string[] } | null => {
|
|
@@ -285,6 +285,18 @@ const handler = createMcpHandler(
|
|
|
285
285
|
}
|
|
286
286
|
)
|
|
287
287
|
|
|
288
|
+
// Dev server restart tool
|
|
289
|
+
server.tool(
|
|
290
|
+
"restart_dev_server",
|
|
291
|
+
TOOL_DESCRIPTIONS.restart_dev_server,
|
|
292
|
+
{
|
|
293
|
+
projectName: z.string().optional().describe("Project name (if multiple dev3000 instances are running)")
|
|
294
|
+
},
|
|
295
|
+
async (params) => {
|
|
296
|
+
return restartDevServer(params)
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
|
|
288
300
|
// Tool that returns monitoring code for Claude to execute
|
|
289
301
|
// TODO: Commenting out for now - need to figure out the right approach for proactive monitoring
|
|
290
302
|
/*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { exec } from "child_process"
|
|
1
|
+
import { exec, spawn } from "child_process"
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "fs"
|
|
3
3
|
import { homedir, tmpdir } from "os"
|
|
4
4
|
import { join } from "path"
|
|
@@ -21,7 +21,10 @@ export const TOOL_DESCRIPTIONS = {
|
|
|
21
21
|
"🔍 **VISUAL DIFF ANALYZER** - Analyzes two screenshots to identify and describe visual differences. Returns detailed instructions for Claude to load and compare the images, focusing on what changed that could cause layout shifts.\n\n🎯 **WHAT IT PROVIDES:**\n• Direct instructions to load both images via Read tool\n• Context about what to look for\n• Guidance on identifying layout shift causes\n• Structured format for easy analysis\n\n💡 **PERFECT FOR:** Understanding what visual changes occurred between before/after frames in CLS detection, identifying elements that appeared/moved/resized.",
|
|
22
22
|
|
|
23
23
|
find_component_source:
|
|
24
|
-
"🔍 **COMPONENT SOURCE FINDER** - Maps DOM elements to their source code by extracting the React component function and finding unique patterns to search for.\n\n🎯 **HOW IT WORKS:**\n• Inspects the element via Chrome DevTools Protocol\n• Extracts the React component function source using .toString()\n• Identifies unique code patterns (specific JSX, classNames, imports)\n• Returns targeted grep patterns to find the exact source file\n\n💡 **PERFECT FOR:** Finding which file contains the code for a specific element, especially useful for CLS debugging when you need to fix layout shifts in specific components."
|
|
24
|
+
"🔍 **COMPONENT SOURCE FINDER** - Maps DOM elements to their source code by extracting the React component function and finding unique patterns to search for.\n\n🎯 **HOW IT WORKS:**\n• Inspects the element via Chrome DevTools Protocol\n• Extracts the React component function source using .toString()\n• Identifies unique code patterns (specific JSX, classNames, imports)\n• Returns targeted grep patterns to find the exact source file\n\n💡 **PERFECT FOR:** Finding which file contains the code for a specific element, especially useful for CLS debugging when you need to fix layout shifts in specific components.",
|
|
25
|
+
|
|
26
|
+
restart_dev_server:
|
|
27
|
+
"🔄 **DEV SERVER RESTART** - Safely restarts the development server while preserving dev3000's monitoring, logs, and browser connection.\n\n🎯 **SMART RESTART LOGIC:**\n• First tries nextjs-dev MCP restart (if available and user has Next.js canary)\n• Falls back to dev3000's own restart mechanism:\n - Kills the old server process on the app port\n - Waits for clean shutdown\n - Spawns a new server with the same command that was originally used\n - Keeps dev3000's MCP server, browser monitoring, and screenshot capture running\n• All logging continues seamlessly - no data loss\n• Browser monitoring stays connected - no need to relaunch Chrome\n\n⚡ **WHEN TO USE:**\n• After modifying next.config.js, middleware, or environment variables\n• When you need a clean restart to clear server state\n• After significant code changes that Next.js HMR can't handle\n• When debugging persistent state or memory issues\n\n⚠️ **CRITICAL - DO NOT:**\n• ❌ NEVER manually run kill commands on the dev server like `pkill -f \"next dev\"` or `lsof -ti :3000 | xargs kill`\n• ❌ NEVER manually start the dev server with `npm run dev`, `pnpm dev`, `next dev`, etc.\n• ✅ ALWAYS use this tool for dev server restarts - it preserves all dev3000 infrastructure\n\n⚠️ **IMPORTANT:**\n• AVOID using this unnecessarily - Next.js HMR handles most changes automatically\n• Only restart when truly needed for config changes or state issues\n• The server will be offline for a few seconds during restart\n• Browser may show connection error briefly while server restarts\n\n💡 **PERFECT FOR:** 'restart the dev server', 'clean restart', 'reload the server' - but only when actually needed, not for regular code changes."
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
// Types
|
|
@@ -365,9 +368,10 @@ export async function fixMyApp({
|
|
|
365
368
|
|
|
366
369
|
// Filter out framework noise (unfixable warnings from Next.js, React, etc.)
|
|
367
370
|
const frameworkNoisePatterns = [
|
|
368
|
-
/link rel=preload.*must have.*valid.*as/i, // Next.js font optimization warning
|
|
371
|
+
/link rel=preload.*must have.*valid.*as/i, // Next.js font optimization warning - not actionable
|
|
369
372
|
/next\/font/i, // Next.js font-related warnings
|
|
370
|
-
/automatically generated/i // Auto-generated code warnings
|
|
373
|
+
/automatically generated/i, // Auto-generated code warnings
|
|
374
|
+
/\[NETWORK\].*\b(200|201|204|304)\b\s+(OK|Created|No Content|Not Modified)/i // Successful HTTP responses - not errors
|
|
371
375
|
]
|
|
372
376
|
|
|
373
377
|
const actionableErrors = allErrors.filter((line) => {
|
|
@@ -2111,6 +2115,57 @@ export async function getMcpCapabilities({
|
|
|
2111
2115
|
}
|
|
2112
2116
|
}
|
|
2113
2117
|
|
|
2118
|
+
/**
|
|
2119
|
+
* Detect if pixel changes represent a layout shift (elements moving) vs content change (images loading)
|
|
2120
|
+
*
|
|
2121
|
+
* Key distinction:
|
|
2122
|
+
* - Layout shifts: Elements move to new positions (top region changes while bottom stays same)
|
|
2123
|
+
* - Content changes: Same regions change in-place (image loads with pixels appearing)
|
|
2124
|
+
*/
|
|
2125
|
+
function detectLayoutShiftVsContentChange(prevPng: PNG, currPng: PNG): { isLayoutShift: boolean; shiftScore: number } {
|
|
2126
|
+
const width = prevPng.width
|
|
2127
|
+
const height = prevPng.height
|
|
2128
|
+
|
|
2129
|
+
// Divide screen into horizontal bands (top, middle, bottom)
|
|
2130
|
+
const bandHeight = Math.floor(height / 8)
|
|
2131
|
+
const bands = Array(8).fill(0)
|
|
2132
|
+
|
|
2133
|
+
// Count changed pixels in each band
|
|
2134
|
+
for (let y = 0; y < height; y++) {
|
|
2135
|
+
const bandIndex = Math.min(Math.floor(y / bandHeight), 7)
|
|
2136
|
+
for (let x = 0; x < width; x++) {
|
|
2137
|
+
const idx = (width * y + x) << 2
|
|
2138
|
+
const rDiff = Math.abs(prevPng.data[idx] - currPng.data[idx])
|
|
2139
|
+
const gDiff = Math.abs(prevPng.data[idx + 1] - currPng.data[idx + 1])
|
|
2140
|
+
const bDiff = Math.abs(prevPng.data[idx + 2] - currPng.data[idx + 2])
|
|
2141
|
+
|
|
2142
|
+
// If any channel differs significantly, count as changed pixel
|
|
2143
|
+
if (rDiff > 30 || gDiff > 30 || bDiff > 30) {
|
|
2144
|
+
bands[bandIndex]++
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// Calculate percentage of pixels changed in each band
|
|
2150
|
+
const pixelsPerBand = width * bandHeight
|
|
2151
|
+
const bandPercentages = bands.map((count) => (count / pixelsPerBand) * 100)
|
|
2152
|
+
|
|
2153
|
+
// Layout shift pattern: High change in top bands (nav/header area), low change in bottom
|
|
2154
|
+
// Content change pattern: Evenly distributed or contained to specific regions
|
|
2155
|
+
const topBandChange = (bandPercentages[0] + bandPercentages[1]) / 2
|
|
2156
|
+
const bottomBandChange = (bandPercentages[6] + bandPercentages[7]) / 2
|
|
2157
|
+
|
|
2158
|
+
// If top 25% of screen has >5% pixel change but bottom has <2% change = layout shift
|
|
2159
|
+
const isLayoutShift = topBandChange > 5 && bottomBandChange < 2 && topBandChange > bottomBandChange * 2
|
|
2160
|
+
|
|
2161
|
+
// Calculate shift score (similar to CLS score)
|
|
2162
|
+
const totalChanged = bands.reduce((sum, count) => sum + count, 0)
|
|
2163
|
+
const totalPixels = width * height
|
|
2164
|
+
const shiftScore = (totalChanged / totalPixels) * 0.1 // Rough CLS equivalent
|
|
2165
|
+
|
|
2166
|
+
return { isLayoutShift, shiftScore }
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2114
2169
|
/**
|
|
2115
2170
|
* Detect jank/layout shifts by comparing screenshots from ScreencastManager
|
|
2116
2171
|
* Returns array of jank detections with timing and visual impact data
|
|
@@ -2249,8 +2304,70 @@ async function detectJankFromScreenshots(_projectName?: string): Promise<{
|
|
|
2249
2304
|
|
|
2250
2305
|
// If we have real CLS data from Chrome's PerformanceObserver, trust it completely
|
|
2251
2306
|
if (realCLSData) {
|
|
2252
|
-
// If Chrome says there are no shifts,
|
|
2307
|
+
// If Chrome says there are no shifts, validate with pixel diff as backup
|
|
2308
|
+
// Chrome's PerformanceObserver can miss very fast hydration shifts
|
|
2253
2309
|
if (realCLSData.shifts.length === 0) {
|
|
2310
|
+
// Run pixel diff validation on early frames (first 1500ms) to catch hydration issues
|
|
2311
|
+
const earlyFrames = sessionFiles.filter((f) => {
|
|
2312
|
+
const timeMatch = f.match(/-(\d+)ms\.png$/)
|
|
2313
|
+
const time = timeMatch ? parseInt(timeMatch[1], 10) : 0
|
|
2314
|
+
return time < 1500 // Hydration window
|
|
2315
|
+
})
|
|
2316
|
+
|
|
2317
|
+
let foundHydrationShift = false
|
|
2318
|
+
|
|
2319
|
+
// Only check consecutive early frames
|
|
2320
|
+
for (let i = 1; i < earlyFrames.length && i < 10; i++) {
|
|
2321
|
+
const prevFile = join(screenshotDir, earlyFrames[i - 1])
|
|
2322
|
+
const currFile = join(screenshotDir, earlyFrames[i])
|
|
2323
|
+
|
|
2324
|
+
try {
|
|
2325
|
+
const prevPng = PNG.sync.read(readFileSync(prevFile))
|
|
2326
|
+
const currPng = PNG.sync.read(readFileSync(currFile))
|
|
2327
|
+
|
|
2328
|
+
if (prevPng.width !== currPng.width || prevPng.height !== currPng.height) {
|
|
2329
|
+
continue
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
// Detect if this is a layout shift vs content change
|
|
2333
|
+
const shiftAnalysis = detectLayoutShiftVsContentChange(prevPng, currPng)
|
|
2334
|
+
|
|
2335
|
+
// If we detect a layout shift (not just content loading), flag it
|
|
2336
|
+
if (shiftAnalysis.isLayoutShift) {
|
|
2337
|
+
foundHydrationShift = true
|
|
2338
|
+
const timeMatch = earlyFrames[i].match(/-(\d+)ms\.png$/)
|
|
2339
|
+
const timeSinceStart = timeMatch ? parseInt(timeMatch[1], 10) : 0
|
|
2340
|
+
|
|
2341
|
+
const mcpPort = process.env.MCP_PORT || "3684"
|
|
2342
|
+
jankDetections.push({
|
|
2343
|
+
timestamp: `${timeSinceStart}ms`,
|
|
2344
|
+
timeSinceStart,
|
|
2345
|
+
visualDiff: shiftAnalysis.shiftScore * 100,
|
|
2346
|
+
severity: "high", // Hydration shifts are always high severity
|
|
2347
|
+
element: "Hydration-related element",
|
|
2348
|
+
clsScore: shiftAnalysis.shiftScore,
|
|
2349
|
+
uxImpact: "🚨 CRITICAL: Fast hydration shift detected - Chrome's observer missed this early shift",
|
|
2350
|
+
beforeFrameUrl: `http://localhost:${mcpPort}/api/screenshots/${earlyFrames[i - 1]}`,
|
|
2351
|
+
afterFrameUrl: `http://localhost:${mcpPort}/api/screenshots/${earlyFrames[i]}`
|
|
2352
|
+
})
|
|
2353
|
+
}
|
|
2354
|
+
} catch {
|
|
2355
|
+
// Skip frames that can't be compared
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// If we found hydration shifts, return them with a note
|
|
2360
|
+
if (foundHydrationShift) {
|
|
2361
|
+
return {
|
|
2362
|
+
detections: jankDetections,
|
|
2363
|
+
sessionId: latestSessionId,
|
|
2364
|
+
totalFrames: sessionFiles.length,
|
|
2365
|
+
screenshotDir,
|
|
2366
|
+
realCLS: { score: 0.05, grade: "good" } // Estimate CLS for hydration shifts
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// Chrome is correct - no shifts detected
|
|
2254
2371
|
return {
|
|
2255
2372
|
detections: [],
|
|
2256
2373
|
sessionId: latestSessionId,
|
|
@@ -3152,3 +3269,213 @@ export async function findComponentSource(params: {
|
|
|
3152
3269
|
}
|
|
3153
3270
|
}
|
|
3154
3271
|
}
|
|
3272
|
+
|
|
3273
|
+
/**
|
|
3274
|
+
* Restart the development server while preserving logs and monitoring
|
|
3275
|
+
*/
|
|
3276
|
+
export async function restartDevServer(params: {
|
|
3277
|
+
projectName?: string
|
|
3278
|
+
}): Promise<{ content: Array<{ type: "text"; text: string }> }> {
|
|
3279
|
+
const { projectName } = params
|
|
3280
|
+
|
|
3281
|
+
try {
|
|
3282
|
+
// Find active session
|
|
3283
|
+
const sessions = findActiveSessions()
|
|
3284
|
+
if (sessions.length === 0) {
|
|
3285
|
+
return {
|
|
3286
|
+
content: [
|
|
3287
|
+
{
|
|
3288
|
+
type: "text",
|
|
3289
|
+
text: "❌ **NO ACTIVE SESSIONS**\n\nNo active dev3000 sessions found. Make sure your app is running with dev3000."
|
|
3290
|
+
}
|
|
3291
|
+
]
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
// Use specified project or first available session
|
|
3296
|
+
let targetSession = sessions[0]
|
|
3297
|
+
if (projectName) {
|
|
3298
|
+
const found = sessions.find((s) => s.projectName === projectName)
|
|
3299
|
+
if (found) {
|
|
3300
|
+
targetSession = found
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
const sessionData = JSON.parse(readFileSync(targetSession.sessionFile, "utf-8"))
|
|
3305
|
+
const appPort = sessionData.appPort
|
|
3306
|
+
const serverCommand = sessionData.serverCommand
|
|
3307
|
+
const cwd = sessionData.cwd
|
|
3308
|
+
|
|
3309
|
+
if (!appPort) {
|
|
3310
|
+
return {
|
|
3311
|
+
content: [
|
|
3312
|
+
{
|
|
3313
|
+
type: "text",
|
|
3314
|
+
text: "❌ **NO APP PORT FOUND**\n\nSession file doesn't contain app port information."
|
|
3315
|
+
}
|
|
3316
|
+
]
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
if (!serverCommand) {
|
|
3321
|
+
return {
|
|
3322
|
+
content: [
|
|
3323
|
+
{
|
|
3324
|
+
type: "text",
|
|
3325
|
+
text: "❌ **NO SERVER COMMAND FOUND**\n\nSession file doesn't contain the original server command. This session may have been created with an older version of dev3000."
|
|
3326
|
+
}
|
|
3327
|
+
]
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
logToDevFile(
|
|
3332
|
+
`Restart Dev Server: Starting restart for project [${targetSession.projectName}] on port ${appPort} with command [${serverCommand}]`
|
|
3333
|
+
)
|
|
3334
|
+
|
|
3335
|
+
// Check if nextjs-dev MCP is available
|
|
3336
|
+
const availableMcps = await discoverAvailableMcps(targetSession.projectName)
|
|
3337
|
+
const hasNextjsDev = availableMcps.includes("nextjs-dev")
|
|
3338
|
+
|
|
3339
|
+
logToDevFile(`Restart Dev Server: Has nextjs-dev MCP: ${hasNextjsDev}`)
|
|
3340
|
+
|
|
3341
|
+
// Try nextjs-dev MCP first if available
|
|
3342
|
+
if (hasNextjsDev) {
|
|
3343
|
+
try {
|
|
3344
|
+
logToDevFile("Restart Dev Server: Attempting to use nextjs-dev MCP restart")
|
|
3345
|
+
|
|
3346
|
+
// Check if nextjs-dev has restart capability
|
|
3347
|
+
const capabilities = await getMcpCapabilities({ mcpName: "nextjs-dev" })
|
|
3348
|
+
const capabilitiesText =
|
|
3349
|
+
capabilities.content[0] && "text" in capabilities.content[0] ? capabilities.content[0].text : ""
|
|
3350
|
+
|
|
3351
|
+
if (capabilitiesText.includes("restart") || capabilitiesText.includes("reload")) {
|
|
3352
|
+
logToDevFile("Restart Dev Server: nextjs-dev MCP has restart capability, delegating")
|
|
3353
|
+
|
|
3354
|
+
return {
|
|
3355
|
+
content: [
|
|
3356
|
+
{
|
|
3357
|
+
type: "text",
|
|
3358
|
+
text: "✅ **DELEGATING TO NEXTJS-DEV MCP**\n\nThe nextjs-dev MCP has restart capabilities. Please use the nextjs-dev MCP restart tool directly for better integration with Next.js."
|
|
3359
|
+
}
|
|
3360
|
+
]
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
logToDevFile("Restart Dev Server: nextjs-dev MCP doesn't have restart capability, falling back")
|
|
3365
|
+
} catch (error) {
|
|
3366
|
+
logToDevFile(`Restart Dev Server: Failed to check nextjs-dev capabilities - ${error}`)
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
// Fallback: Use dev3000's own restart mechanism
|
|
3371
|
+
logToDevFile("Restart Dev Server: Using dev3000 restart mechanism")
|
|
3372
|
+
|
|
3373
|
+
// Kill processes on the app port
|
|
3374
|
+
const killCommand = `lsof -ti :${appPort} | xargs kill 2>/dev/null || true`
|
|
3375
|
+
logToDevFile(`Restart Dev Server: Executing kill command: ${killCommand}`)
|
|
3376
|
+
|
|
3377
|
+
try {
|
|
3378
|
+
await execAsync(killCommand)
|
|
3379
|
+
logToDevFile("Restart Dev Server: Kill command executed successfully")
|
|
3380
|
+
} catch (error) {
|
|
3381
|
+
logToDevFile(`Restart Dev Server: Kill command failed (may be ok) - ${error}`)
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
// Wait for clean shutdown
|
|
3385
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
3386
|
+
|
|
3387
|
+
// Check if port is now free
|
|
3388
|
+
const checkCommand = `lsof -ti :${appPort}`
|
|
3389
|
+
let portFree = false
|
|
3390
|
+
try {
|
|
3391
|
+
const { stdout } = await execAsync(checkCommand)
|
|
3392
|
+
portFree = stdout.trim() === ""
|
|
3393
|
+
logToDevFile(`Restart Dev Server: Port check result - free: ${portFree}`)
|
|
3394
|
+
} catch {
|
|
3395
|
+
// Command failed means no process on port (port is free)
|
|
3396
|
+
portFree = true
|
|
3397
|
+
logToDevFile("Restart Dev Server: Port is free (lsof returned no results)")
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
if (!portFree) {
|
|
3401
|
+
return {
|
|
3402
|
+
content: [
|
|
3403
|
+
{
|
|
3404
|
+
type: "text",
|
|
3405
|
+
text: `⚠️ **PORT STILL IN USE**\n\nFailed to free port ${appPort}. There may be a process that couldn't be killed.\n\nTry manually killing the process:\n\`\`\`bash\nlsof -ti :${appPort} | xargs kill -9\n\`\`\``
|
|
3406
|
+
}
|
|
3407
|
+
]
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
logToDevFile("Restart Dev Server: Port is now free, spawning new server process")
|
|
3412
|
+
|
|
3413
|
+
// Spawn new server process
|
|
3414
|
+
try {
|
|
3415
|
+
const serverProcess = spawn(serverCommand, {
|
|
3416
|
+
stdio: "inherit", // Inherit stdio so output goes to dev3000's logs
|
|
3417
|
+
shell: true,
|
|
3418
|
+
detached: true, // Run independently
|
|
3419
|
+
cwd: cwd || process.cwd() // Use original working directory
|
|
3420
|
+
})
|
|
3421
|
+
|
|
3422
|
+
// Unref so this process doesn't keep MCP server alive
|
|
3423
|
+
serverProcess.unref()
|
|
3424
|
+
|
|
3425
|
+
logToDevFile(`Restart Dev Server: Spawned new server process with PID ${serverProcess.pid}`)
|
|
3426
|
+
|
|
3427
|
+
// Wait a moment for server to start
|
|
3428
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
3429
|
+
|
|
3430
|
+
// Check if server is actually running on the port
|
|
3431
|
+
try {
|
|
3432
|
+
const { stdout: checkResult } = await execAsync(`lsof -ti :${appPort}`)
|
|
3433
|
+
const isRunning = checkResult.trim() !== ""
|
|
3434
|
+
|
|
3435
|
+
if (isRunning) {
|
|
3436
|
+
logToDevFile("Restart Dev Server: Server successfully restarted and running on port")
|
|
3437
|
+
return {
|
|
3438
|
+
content: [
|
|
3439
|
+
{
|
|
3440
|
+
type: "text",
|
|
3441
|
+
text: `✅ **DEV SERVER RESTARTED**\n\nSuccessfully restarted the development server on port ${appPort}.\n\n🎯 **STATUS:**\n• Old server process: Killed\n• New server process: Running (PID ${serverProcess.pid})\n• Port ${appPort}: Active\n• Browser monitoring: Unchanged\n• Logs: Still being captured\n\n💡 The server has been restarted while keeping dev3000's monitoring, screenshots, and logging intact.`
|
|
3442
|
+
}
|
|
3443
|
+
]
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
logToDevFile("Restart Dev Server: Server process spawned but not yet listening on port (may still be starting)")
|
|
3447
|
+
} catch {
|
|
3448
|
+
logToDevFile("Restart Dev Server: Server process spawned but not yet listening on port (may still be starting)")
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
return {
|
|
3452
|
+
content: [
|
|
3453
|
+
{
|
|
3454
|
+
type: "text",
|
|
3455
|
+
text: `🔄 **DEV SERVER RESTARTING**\n\nStarted a new server process (PID ${serverProcess.pid}).\n\n⏳ **STATUS:**\n• Old server: Killed\n• New server: Starting (may take a few moments)\n• Command: \`${serverCommand}\`\n• Port: ${appPort}\n\nThe server is restarting. Check the dev3000 logs to see when it's ready.`
|
|
3456
|
+
}
|
|
3457
|
+
]
|
|
3458
|
+
}
|
|
3459
|
+
} catch (spawnError) {
|
|
3460
|
+
logToDevFile(`Restart Dev Server: Failed to spawn new server process - ${spawnError}`)
|
|
3461
|
+
return {
|
|
3462
|
+
content: [
|
|
3463
|
+
{
|
|
3464
|
+
type: "text",
|
|
3465
|
+
text: `❌ **RESTART FAILED**\n\nFailed to start new server process.\n\n**Error:** ${spawnError instanceof Error ? spawnError.message : String(spawnError)}\n\n**Command:** \`${serverCommand}\`\n\nThe old server was killed but the new one failed to start. You may need to manually restart dev3000.`
|
|
3466
|
+
}
|
|
3467
|
+
]
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
} catch (error) {
|
|
3471
|
+
logToDevFile(`Restart Dev Server: Error - ${error}`)
|
|
3472
|
+
return {
|
|
3473
|
+
content: [
|
|
3474
|
+
{
|
|
3475
|
+
type: "text",
|
|
3476
|
+
text: `❌ **ERROR**\n\n${error instanceof Error ? error.message : String(error)}`
|
|
3477
|
+
}
|
|
3478
|
+
]
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
package/mcp-server/app/page.tsx
CHANGED
package/package.json
CHANGED
/package/mcp-server/.next/static/{4QTQwT0vriZN0rBeHTIWl → eVL_05d0pOH_qw2twMoct}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/mcp-server/.next/static/{4QTQwT0vriZN0rBeHTIWl → eVL_05d0pOH_qw2twMoct}/_ssgManifest.js
RENAMED
|
File without changes
|