code-to-design 0.1.4 → 0.1.5

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.
@@ -1,7 +1,7 @@
1
1
  // src/commands/scan.ts
2
2
  import { join as join9 } from "path";
3
3
  import { rm, mkdir as mkdir3 } from "fs/promises";
4
- import { existsSync as existsSync6, watch as fsWatch } from "fs";
4
+ import { existsSync as existsSync7, watch as fsWatch } from "fs";
5
5
 
6
6
  // ../core/src/discovery/route-scanner.ts
7
7
  import { readdir, stat } from "fs/promises";
@@ -906,6 +906,7 @@ async function preRenderPages(tasks, options) {
906
906
  // src/server/canvas-server.ts
907
907
  import { createServer as createServer2 } from "http";
908
908
  import { join as join7 } from "path";
909
+ import { existsSync as existsSync5 } from "fs";
909
910
  import sirv from "sirv";
910
911
 
911
912
  // src/server/api-routes.ts
@@ -1106,10 +1107,12 @@ function tryListen(requestHandler, port) {
1106
1107
  });
1107
1108
  }
1108
1109
  async function startCanvasServer(options) {
1109
- const { port = 4800, canvasDir, c2dDir } = options;
1110
+ const { port = 4800, canvasDir, c2dDir, projectRoot } = options;
1110
1111
  const canvasHandler = sirv(canvasDir, { single: true, dev: true });
1111
1112
  const rendersDir = join7(c2dDir, "renders");
1112
1113
  const rendersHandler = sirv(rendersDir, { dev: true });
1114
+ const publicDir = projectRoot ? join7(projectRoot, "public") : null;
1115
+ const publicHandler = publicDir && existsSync5(publicDir) ? sirv(publicDir, { dev: true }) : null;
1113
1116
  const requestHandler = async (req, res) => {
1114
1117
  const url = req.url ?? "/";
1115
1118
  const method = req.method ?? "GET";
@@ -1143,6 +1146,15 @@ async function startCanvasServer(options) {
1143
1146
  });
1144
1147
  return;
1145
1148
  }
1149
+ if (publicHandler) {
1150
+ publicHandler(req, res, () => {
1151
+ canvasHandler(req, res, () => {
1152
+ res.writeHead(404);
1153
+ res.end("Not found");
1154
+ });
1155
+ });
1156
+ return;
1157
+ }
1146
1158
  canvasHandler(req, res, () => {
1147
1159
  res.writeHead(404);
1148
1160
  res.end("Not found");
@@ -1163,14 +1175,14 @@ async function startCanvasServer(options) {
1163
1175
  }
1164
1176
 
1165
1177
  // src/config.ts
1166
- import { existsSync as existsSync5 } from "fs";
1178
+ import { existsSync as existsSync6 } from "fs";
1167
1179
  import { readFile as readFile4 } from "fs/promises";
1168
1180
  import { join as join8 } from "path";
1169
1181
  var DEFAULT_PORT = 4800;
1170
1182
  async function loadConfig(projectRoot) {
1171
1183
  let fileConfig = {};
1172
1184
  const configPath = join8(projectRoot, "c2d.config.js");
1173
- if (existsSync5(configPath)) {
1185
+ if (existsSync6(configPath)) {
1174
1186
  try {
1175
1187
  const mod = await import(configPath);
1176
1188
  fileConfig = mod.default || mod;
@@ -1187,12 +1199,12 @@ async function loadConfig(projectRoot) {
1187
1199
  };
1188
1200
  }
1189
1201
  async function detectNextJsProject(projectRoot) {
1190
- const hasNextConfig = existsSync5(join8(projectRoot, "next.config.ts")) || existsSync5(join8(projectRoot, "next.config.js")) || existsSync5(join8(projectRoot, "next.config.mjs"));
1202
+ const hasNextConfig = existsSync6(join8(projectRoot, "next.config.ts")) || existsSync6(join8(projectRoot, "next.config.js")) || existsSync6(join8(projectRoot, "next.config.mjs"));
1191
1203
  let appDir = join8(projectRoot, "app");
1192
- let hasAppDir = existsSync5(appDir);
1204
+ let hasAppDir = existsSync6(appDir);
1193
1205
  if (!hasAppDir) {
1194
1206
  appDir = join8(projectRoot, "src", "app");
1195
- hasAppDir = existsSync5(appDir);
1207
+ hasAppDir = existsSync6(appDir);
1196
1208
  }
1197
1209
  let projectName = "unknown";
1198
1210
  try {
@@ -1264,12 +1276,12 @@ async function runScan(options) {
1264
1276
  success(`App directory: ${project.appDir}`);
1265
1277
  const c2dDir = join9(projectRoot, ".c2d");
1266
1278
  if (skipRender) {
1267
- if (!existsSync6(join9(c2dDir, "manifest.json"))) {
1279
+ if (!existsSync7(join9(c2dDir, "manifest.json"))) {
1268
1280
  error("No previous renders found. Run without --skip-render first.");
1269
1281
  process.exit(1);
1270
1282
  }
1271
1283
  log("Skipping render, using existing canvas data...");
1272
- await startServer(c2dDir, config.port, open);
1284
+ await startServer(c2dDir, config.port, open, projectRoot);
1273
1285
  return;
1274
1286
  }
1275
1287
  header("Discovering routes...");
@@ -1316,7 +1328,7 @@ async function runScan(options) {
1316
1328
  success("Using fallback mocks (no API key or no API dependencies)");
1317
1329
  }
1318
1330
  header(`Pre-rendering ${renderTasks.length} page states...`);
1319
- if (existsSync6(join9(c2dDir, "renders"))) {
1331
+ if (existsSync7(join9(c2dDir, "renders"))) {
1320
1332
  await rm(join9(c2dDir, "renders"), { recursive: true });
1321
1333
  }
1322
1334
  await mkdir3(c2dDir, { recursive: true });
@@ -1342,7 +1354,7 @@ async function runScan(options) {
1342
1354
  }
1343
1355
  }
1344
1356
  if (watch) {
1345
- const server = await startServerNonBlocking(c2dDir, config.port, open);
1357
+ const server = await startServerNonBlocking(c2dDir, config.port, open, projectRoot);
1346
1358
  watchAndRerender(projectRoot, project.appDir, c2dDir, config);
1347
1359
  await new Promise((resolve2) => {
1348
1360
  const shutdown = async () => {
@@ -1354,10 +1366,10 @@ async function runScan(options) {
1354
1366
  process.on("SIGTERM", shutdown);
1355
1367
  });
1356
1368
  } else {
1357
- await startServer(c2dDir, config.port, open);
1369
+ await startServer(c2dDir, config.port, open, projectRoot);
1358
1370
  }
1359
1371
  }
1360
- async function startServer(c2dDir, port, open) {
1372
+ async function startServer(c2dDir, port, open, projectRoot) {
1361
1373
  header("Starting canvas server...");
1362
1374
  const canvasDir = await resolveCanvasDir(c2dDir);
1363
1375
  if (!canvasDir) {
@@ -1366,7 +1378,8 @@ async function startServer(c2dDir, port, open) {
1366
1378
  const server = await startCanvasServer({
1367
1379
  port,
1368
1380
  canvasDir,
1369
- c2dDir
1381
+ c2dDir,
1382
+ projectRoot
1370
1383
  });
1371
1384
  success(`Canvas server running at ${server.url}`);
1372
1385
  log("Share this URL with your team for collaborative review");
@@ -1388,7 +1401,7 @@ async function startServer(c2dDir, port, open) {
1388
1401
  process.on("SIGTERM", shutdown);
1389
1402
  });
1390
1403
  }
1391
- async function startServerNonBlocking(c2dDir, port, open) {
1404
+ async function startServerNonBlocking(c2dDir, port, open, projectRoot) {
1392
1405
  header("Starting canvas server...");
1393
1406
  const canvasDir = await resolveCanvasDir(c2dDir);
1394
1407
  if (!canvasDir) {
@@ -1397,7 +1410,8 @@ async function startServerNonBlocking(c2dDir, port, open) {
1397
1410
  const server = await startCanvasServer({
1398
1411
  port,
1399
1412
  canvasDir,
1400
- c2dDir
1413
+ c2dDir,
1414
+ projectRoot
1401
1415
  });
1402
1416
  success(`Canvas server running at ${server.url}`);
1403
1417
  log("Share this URL with your team for collaborative review");
@@ -1418,13 +1432,13 @@ async function resolveCanvasDir(c2dDir) {
1418
1432
  let dir = dirname3(__filename);
1419
1433
  for (let i = 0; i < 5; i++) {
1420
1434
  const candidate = join9(dir, "canvas-dist");
1421
- if (existsSync6(candidate) && existsSync6(join9(candidate, "index.html"))) {
1435
+ if (existsSync7(candidate) && existsSync7(join9(candidate, "index.html"))) {
1422
1436
  return candidate;
1423
1437
  }
1424
1438
  dir = dirname3(dir);
1425
1439
  }
1426
1440
  const monorepoDev = join9(dirname3(__filename), "..", "..", "..", "..", "apps", "canvas", "dist");
1427
- if (existsSync6(monorepoDev) && existsSync6(join9(monorepoDev, "index.html"))) {
1441
+ if (existsSync7(monorepoDev) && existsSync7(join9(monorepoDev, "index.html"))) {
1428
1442
  return monorepoDev;
1429
1443
  }
1430
1444
  const placeholder = join9(c2dDir, "_canvas");
@@ -1475,7 +1489,7 @@ File changed: ${filename}. Re-rendering...`);
1475
1489
  });
1476
1490
  }
1477
1491
  }
1478
- if (existsSync6(join9(c2dDir, "renders"))) {
1492
+ if (existsSync7(join9(c2dDir, "renders"))) {
1479
1493
  await rm(join9(c2dDir, "renders"), { recursive: true });
1480
1494
  }
1481
1495
  await mkdir3(c2dDir, { recursive: true });
@@ -1501,4 +1515,4 @@ export {
1501
1515
  detectNextJsProject,
1502
1516
  runScan
1503
1517
  };
1504
- //# sourceMappingURL=chunk-BHEMO5RW.js.map
1518
+ //# sourceMappingURL=chunk-WX4KLWOS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/scan.ts","../../core/src/discovery/route-scanner.ts","../../core/src/analysis/code-analyzer.ts","../../core/src/analysis/auth-detector.ts","../../core/src/mock/types.ts","../../core/src/mock/llm-client.ts","../../core/src/mock/prompt-templates.ts","../../core/src/mock/mock-generator.ts","../../core/src/render/pre-renderer.ts","../../core/src/render/dev-server.ts","../src/server/canvas-server.ts","../src/server/api-routes.ts","../src/config.ts","../src/utils/progress.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { rm, mkdir } from 'node:fs/promises';\nimport { existsSync, watch as fsWatch } from 'node:fs';\nimport {\n scanRoutes,\n analyzePage,\n generateMocks,\n preRenderPages,\n type RenderTask,\n type MockGeneratorOptions,\n} from '@code-to-design/core';\nimport { startCanvasServer } from '../server/canvas-server.js';\nimport { loadConfig, detectNextJsProject } from '../config.js';\nimport * as ui from '../utils/progress.js';\n\n/**\n * Main scan command — runs the full Code to Design pipeline.\n *\n * 1. Detect project type\n * 2. Discover routes\n * 3. Analyze code + generate mocks\n * 4. Pre-render pages\n * 5. Start canvas server\n */\nexport async function runScan(options: {\n projectRoot: string;\n skipRender?: boolean;\n open?: boolean;\n watch?: boolean;\n}): Promise<void> {\n const { projectRoot, skipRender = false, open = true, watch = false } = options;\n\n ui.banner();\n\n // Load config\n const config = await loadConfig(projectRoot);\n\n // Step 1: Detect project\n ui.header('Detecting project...');\n const project = await detectNextJsProject(projectRoot);\n\n if (!project.isNextJs) {\n ui.error('Not a Next.js project (no next.config.ts/js/mjs found).');\n ui.log('Code to Design currently supports Next.js App Router projects only.');\n process.exit(1);\n }\n\n if (!project.appDir) {\n ui.error('No app/ directory found. Code to Design requires Next.js App Router.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName}`);\n ui.success(`App directory: ${project.appDir}`);\n\n const c2dDir = join(projectRoot, '.c2d');\n\n // If --skip-render, just start the server with existing renders\n if (skipRender) {\n if (!existsSync(join(c2dDir, 'manifest.json'))) {\n ui.error('No previous renders found. Run without --skip-render first.');\n process.exit(1);\n }\n ui.log('Skipping render, using existing canvas data...');\n await startServer(c2dDir, config.port, open, projectRoot);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const routes = await scanRoutes({ appDir: project.appDir });\n\n if (routes.length === 0) {\n ui.error('No routes found in app/ directory.');\n process.exit(1);\n }\n\n // Filter excluded routes\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n ui.success(`Found ${filteredRoutes.length} routes`);\n for (const r of filteredRoutes) {\n ui.log(` ${r.urlPath}${r.isDynamic ? ' [dynamic]' : ''}`);\n }\n\n // Step 3: Check API key\n if (!config.apiKey) {\n ui.warn('No API key configured. Mock generation will use fallback data.');\n ui.log('Set C2D_API_KEY env var or add apiKey to c2d.config.js');\n }\n\n // Step 4: Analyze and generate mocks\n ui.header('Analyzing code and generating mocks...');\n\n const renderTasks: RenderTask[] = [];\n let totalTokens = { input: 0, output: 0 };\n\n const mockOptions: MockGeneratorOptions = {\n apiKey: config.apiKey,\n };\n\n for (let i = 0; i < filteredRoutes.length; i++) {\n const route = filteredRoutes[i];\n ui.step(i + 1, filteredRoutes.length, `${route.urlPath}`);\n\n // Analyze page\n const analysis = await analyzePage(route, { projectRoot });\n\n // Generate mocks\n const { configs, tokenUsage } = await generateMocks(analysis, mockOptions);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n\n // Create render tasks\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n if (totalTokens.input > 0) {\n ui.success(`Mock generation complete (${totalTokens.input} input tokens, ${totalTokens.output} output tokens)`);\n } else {\n ui.success('Using fallback mocks (no API key or no API dependencies)');\n }\n\n // Step 5: Pre-render\n ui.header(`Pre-rendering ${renderTasks.length} page states...`);\n\n // Clear previous renders but preserve comments\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n const { results, manifest } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n onProgress: (completed, total, result) => {\n const pct = Math.round((completed / total) * 100);\n const icon = result.success ? '✓' : '✗';\n const label = `${result.route.urlPath} [${result.stateName}]`;\n process.stdout.write(`\\r ${icon} ${completed}/${total} (${pct}%) ${label}${''.padEnd(20)}`);\n if (completed === total) process.stdout.write('\\n');\n },\n });\n\n const successCount = results.filter((r) => r.success).length;\n const failCount = results.filter((r) => !r.success).length;\n\n ui.success(`Rendered ${successCount}/${results.length} pages`);\n if (failCount > 0) {\n ui.warn(`${failCount} pages failed to render`);\n for (const r of results.filter((r) => !r.success)) {\n ui.error(` ${r.route.urlPath} [${r.stateName}]: ${r.error}`);\n }\n }\n\n // Step 6: Start canvas server\n if (watch) {\n // In watch mode, start the server without blocking so we can watch for changes\n const server = await startServerNonBlocking(c2dDir, config.port, open, projectRoot);\n watchAndRerender(projectRoot, project.appDir!, c2dDir, config);\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n } else {\n await startServer(c2dDir, config.port, open, projectRoot);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean, projectRoot?: string): Promise<void> {\n ui.header('Starting canvas server...');\n\n // Resolve canvas app directory: find canvas-dist relative to this package\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Press Ctrl+C to stop\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n}\n\nasync function startServerNonBlocking(\n c2dDir: string,\n port: number,\n open: boolean,\n projectRoot?: string,\n): Promise<{ url: string; close: () => Promise<void> }> {\n ui.header('Starting canvas server...');\n\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir: canvasDir!,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Watching for file changes...\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n return server;\n}\n\n/**\n * Find the canvas-dist directory by walking up from the module's location\n * until we find a directory containing canvas-dist/.\n * Works in both npm-installed and monorepo-dev environments.\n */\nasync function resolveCanvasDir(c2dDir: string): Promise<string> {\n const { fileURLToPath } = await import('node:url');\n const { dirname } = await import('node:path');\n const __filename = fileURLToPath(import.meta.url);\n\n // Walk up from the current file's directory to find canvas-dist/\n let dir = dirname(__filename);\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, 'canvas-dist');\n if (existsSync(candidate) && existsSync(join(candidate, 'index.html'))) {\n return candidate;\n }\n dir = dirname(dir);\n }\n\n // Fallback: try monorepo dev location\n const monorepoDev = join(dirname(__filename), '..', '..', '..', '..', 'apps', 'canvas', 'dist');\n if (existsSync(monorepoDev) && existsSync(join(monorepoDev, 'index.html'))) {\n return monorepoDev;\n }\n\n // Last resort: write placeholder\n const placeholder = join(c2dDir, '_canvas');\n await mkdir(placeholder, { recursive: true });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(join(placeholder, 'index.html'), `<!DOCTYPE html><html><body>\n <h1>Code to Design</h1>\n <p>Canvas app not built. Run: <code>cd apps/canvas && npx vite build</code></p>\n <p><a href=\"/api/manifest\">View Manifest</a></p>\n </body></html>`);\n return placeholder;\n}\n\n/** File extensions to watch for changes. */\nconst WATCH_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.css']);\n\n/** Directories and patterns to ignore during watch. */\nfunction shouldIgnoreFile(filename: string | null): boolean {\n if (!filename) return true;\n const ignored = ['node_modules', '.next', '.c2d', '.git'];\n if (ignored.some((dir) => filename.includes(dir))) return true;\n const ext = filename.slice(filename.lastIndexOf('.'));\n return !WATCH_EXTENSIONS.has(ext);\n}\n\nfunction watchAndRerender(\n projectRoot: string,\n appDir: string,\n c2dDir: string,\n config: Awaited<ReturnType<typeof loadConfig>>,\n): void {\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n let isRendering = false;\n\n ui.log(`Watching ${appDir} for changes...`);\n\n fsWatch(appDir, { recursive: true }, (_event, filename) => {\n if (shouldIgnoreFile(filename as string | null)) return;\n\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (isRendering) return;\n isRendering = true;\n\n ui.log(`\\nFile changed: ${filename}. Re-rendering...`);\n\n try {\n // Re-discover routes\n const routes = await scanRoutes({ appDir });\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n // Re-analyze and generate mocks\n const renderTasks: RenderTask[] = [];\n const mockOptions: MockGeneratorOptions = { apiKey: config.apiKey };\n\n for (const route of filteredRoutes) {\n const analysis = await analyzePage(route, { projectRoot });\n const { configs } = await generateMocks(analysis, mockOptions);\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n // Clear previous renders\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n // Pre-render\n const { results } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n });\n\n const successCount = results.filter((r) => r.success).length;\n ui.success(`Re-render complete. ${successCount} pages updated.`);\n } catch (err: any) {\n ui.error(`Re-render failed: ${err.message || err}`);\n } finally {\n isRendering = false;\n }\n }, 500);\n });\n}\n","import { readdir, stat } from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport { RouteInfo, RouteParam, ScanOptions } from './types.js';\n\nconst PAGE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx']);\nconst PAGE_BASENAMES = new Set(['page']);\n\n/**\n * Check if a filename is a page file (page.tsx, page.js, etc.)\n */\nfunction isPageFile(filename: string): boolean {\n const ext = extname(filename);\n const basename = filename.slice(0, -ext.length);\n return PAGE_EXTENSIONS.has(ext) && PAGE_BASENAMES.has(basename);\n}\n\n/**\n * Check if a directory should be skipped entirely.\n */\nfunction shouldSkipDir(name: string): boolean {\n // Private folders\n if (name.startsWith('_')) return true;\n // Parallel route slots\n if (name.startsWith('@')) return true;\n // Intercepting routes\n if (name.startsWith('(.)') || name.startsWith('(..)')) return true;\n // Build artifacts and dependencies\n if (name === 'node_modules' || name === '.next') return true;\n return false;\n}\n\n/**\n * Check if a directory is a route group (parenthesized name like \"(auth)\").\n * Route groups are stripped from the URL but recursed into.\n */\nfunction isRouteGroup(name: string): boolean {\n return name.startsWith('(') && name.endsWith(')') && !name.startsWith('(.');\n}\n\n/**\n * Parse a dynamic route segment and extract parameter info.\n * Returns null if the segment is not dynamic.\n */\nfunction parseDynamicSegment(segment: string): RouteParam | null {\n // Optional catch-all: [[...param]]\n const optionalCatchAll = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n if (optionalCatchAll) {\n return { name: optionalCatchAll[1], isCatchAll: true, isOptional: true };\n }\n\n // Required catch-all: [...param]\n const catchAll = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n if (catchAll) {\n return { name: catchAll[1], isCatchAll: true, isOptional: false };\n }\n\n // Single dynamic: [param]\n const dynamic = segment.match(/^\\[(.+)\\]$/);\n if (dynamic) {\n return { name: dynamic[1], isCatchAll: false, isOptional: false };\n }\n\n return null;\n}\n\n/**\n * Convert a dynamic segment to a URL-friendly representation.\n */\nfunction segmentToUrlPart(segment: string): string {\n const param = parseDynamicSegment(segment);\n if (!param) return segment;\n\n if (param.isCatchAll && param.isOptional) return `:${param.name}*`;\n if (param.isCatchAll) return `:${param.name}+`;\n return `:${param.name}`;\n}\n\n/**\n * Recursively scan a directory for Next.js App Router page files.\n */\nasync function scanDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPageFile(entry)) {\n const urlPath = '/' + urlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...params],\n isDynamic: params.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n if (shouldSkipDir(entry)) continue;\n\n if (isRouteGroup(entry)) {\n // Route groups: recurse but don't add to URL\n const nested = await scanDir(entryPath, urlSegments, params);\n routes.push(...nested);\n } else {\n // Regular or dynamic segment\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n }\n\n return routes;\n}\n\n/**\n * Scan a Next.js App Router `app/` directory and extract all renderable routes.\n *\n * Follows Next.js conventions:\n * - page.{js,jsx,ts,tsx} files define renderable routes\n * - Route groups (name) are stripped from URLs\n * - Private folders _name are skipped\n * - Parallel routes @slot are skipped\n * - Intercepting routes (.) are skipped\n * - Dynamic routes [param] are included with parameter metadata\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir } = options;\n\n const dirStat = await stat(appDir).catch(() => null);\n if (!dirStat || !dirStat.isDirectory()) {\n throw new Error(`App directory not found: ${appDir}`);\n }\n\n const routes = await scanDir(appDir, [], []);\n\n // Sort routes for consistent output\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n\n return routes;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join, dirname, resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type { PageAnalysis, AnalyzeOptions } from './types.js';\nimport { detectAuth } from './auth-detector.js';\n\nconst DEFAULT_MAX_TOKENS = 8000;\nconst CHARS_PER_TOKEN = 4; // rough approximation\n\n/**\n * Extract import paths from TypeScript/JavaScript source code.\n * Uses regex — does not handle barrel exports or re-exports.\n */\nfunction extractImportPaths(source: string): string[] {\n const paths: string[] = [];\n // Match: import ... from '...' and import '...'\n const regex = /import\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n paths.push(match[1]);\n }\n return paths;\n}\n\n/**\n * Resolve tsconfig path aliases (e.g., @/lib/api → /absolute/path/lib/api).\n * Returns an absolute path when aliases contain absolute base paths.\n */\nfunction resolvePathAlias(\n importPath: string,\n aliases: Record<string, string>,\n): string | null {\n for (const [pattern, replacement] of Object.entries(aliases)) {\n const prefix = pattern.replace(/\\*$/, '');\n if (importPath.startsWith(prefix)) {\n const rest = importPath.slice(prefix.length);\n return replacement.replace(/\\*$/, '') + rest;\n }\n }\n return null;\n}\n\n/**\n * Read tsconfig.json and extract path aliases.\n */\nasync function readPathAliases(projectRoot: string): Promise<Record<string, string>> {\n const aliases: Record<string, string> = {};\n\n for (const filename of ['tsconfig.json', 'jsconfig.json']) {\n const configPath = join(projectRoot, filename);\n if (!existsSync(configPath)) continue;\n\n try {\n const content = await readFile(configPath, 'utf-8');\n // Strip JSON5-style comments while preserving // inside strings.\n // Match strings first (to skip them), then line & block comments.\n const stripped = content.replace(\n /\"(?:[^\"\\\\]|\\\\.)*\"|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm,\n (match) => (match.startsWith('\"') ? match : ''),\n );\n const config = JSON.parse(stripped);\n const paths = config.compilerOptions?.paths;\n const baseUrl = config.compilerOptions?.baseUrl || '.';\n const resolvedBaseUrl = resolve(projectRoot, baseUrl);\n\n if (paths) {\n for (const [key, values] of Object.entries(paths)) {\n const targets = values as string[];\n if (targets.length > 0) {\n // Store as absolute path for reliable resolution\n aliases[key] = join(resolvedBaseUrl, targets[0]);\n }\n }\n }\n } catch {\n // Can't parse tsconfig — skip aliases\n }\n }\n\n return aliases;\n}\n\n/**\n * Try to resolve an import path to an actual file.\n */\nfunction resolveImportToFile(importPath: string, fromDir: string): string | null {\n // Try exact path first, then with extensions\n const extensions = ['.ts', '.tsx', '.js', '.jsx'];\n const candidates: string[] = [];\n\n const resolved = resolve(fromDir, importPath);\n\n // Try exact\n candidates.push(resolved);\n // Try with extensions\n for (const ext of extensions) {\n candidates.push(resolved + ext);\n }\n // Try as directory with index\n for (const ext of extensions) {\n candidates.push(join(resolved, `index${ext}`));\n }\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Trace imports from a source file, up to maxDepth levels deep.\n * Returns a map of filePath → source content.\n */\nasync function traceImports(\n filePath: string,\n projectRoot: string,\n aliases: Record<string, string>,\n maxDepth: number,\n visited: Set<string> = new Set(),\n): Promise<Map<string, string>> {\n const results = new Map<string, string>();\n\n if (visited.has(filePath) || maxDepth < 0) return results;\n visited.add(filePath);\n\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n return results;\n }\n\n results.set(filePath, source);\n\n const importPaths = extractImportPaths(source);\n const fileDir = dirname(filePath);\n\n for (const importPath of importPaths) {\n // Skip node_modules imports\n if (!importPath.startsWith('.') && !importPath.startsWith('@/') && !importPath.startsWith('~/')) {\n // Check if it's a path alias\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (!aliasResolved) continue;\n\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else if (importPath.startsWith('.')) {\n // Relative import\n const resolved = resolveImportToFile(importPath, fileDir);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else {\n // Path alias (e.g., @/lib/api-client)\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (aliasResolved) {\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Estimate token count from a string (rough: ~4 chars per token).\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\n/**\n * Check if source code contains API call patterns.\n */\nfunction hasApiCalls(source: string): boolean {\n return /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\buseQuery\\b/.test(source)\n || /\\buseMutation\\b/.test(source)\n || /\\bapiRequest\\b/.test(source)\n || /\\bgetServerSideProps\\b/.test(source)\n || /\\bgetStaticProps\\b/.test(source)\n || /API_BASE_URL/.test(source)\n || /['\"]\\/api\\//.test(source)\n // Detect imports from api/client modules (common naming patterns)\n || /from\\s+['\"].*api[-_]?client.*['\"]/.test(source)\n || /from\\s+['\"].*\\/api['\"]/.test(source)\n || /from\\s+['\"].*\\/services\\//.test(source);\n}\n\n/**\n * Analyze a single page: read its source, trace imports, detect auth,\n * and produce a context string suitable for LLM mock generation.\n */\nexport async function analyzePage(\n route: RouteInfo,\n options: AnalyzeOptions,\n): Promise<PageAnalysis> {\n const { projectRoot, maxTokensPerPage = DEFAULT_MAX_TOKENS } = options;\n const maxChars = maxTokensPerPage * CHARS_PER_TOKEN;\n\n const aliases = await readPathAliases(projectRoot);\n\n // Trace imports from the page file, up to 2 levels deep\n const tracedFiles = await traceImports(route.filePath, projectRoot, aliases, 2);\n\n const resolvedImports = [...tracedFiles.keys()].filter(p => p !== route.filePath);\n const allSources = [...tracedFiles.values()];\n\n // Build the source context with file headers\n let sourceContext = '';\n for (const [filePath, content] of tracedFiles) {\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length + 1)\n : filePath;\n const section = `\\n// === ${relativePath} ===\\n${content}\\n`;\n\n if (sourceContext.length + section.length > maxChars) {\n // Truncation: include just the page file and skip the rest\n break;\n }\n sourceContext += section;\n }\n\n // Detect auth patterns\n const authConfig = await detectAuth(projectRoot, allSources);\n\n // Check for API dependencies — check both the truncated context and all traced sources\n const combinedSource = allSources.join('\\n');\n const hasApi = hasApiCalls(sourceContext) || hasApiCalls(combinedSource);\n\n // Collect unresolved imports\n const allImportPaths = allSources.flatMap(extractImportPaths);\n const resolvedSet = new Set(resolvedImports.map(p => p));\n const unresolvedImports = allImportPaths\n .filter(p => p.startsWith('.') || p.startsWith('@/') || p.startsWith('~/'))\n .filter(p => {\n // Check if this import was resolved to any file\n const aliasResolved = resolvePathAlias(p, aliases);\n const checkPath = aliasResolved\n ? resolveImportToFile(aliasResolved, projectRoot)\n : resolveImportToFile(p, dirname(route.filePath));\n return !checkPath;\n });\n\n return {\n route,\n sourceContext,\n resolvedImports,\n unresolvedImports: [...new Set(unresolvedImports)],\n authConfig,\n hasApiDependencies: hasApi,\n estimatedTokens: estimateTokens(sourceContext),\n };\n}\n\n/**\n * Analyze all discovered routes in a project.\n */\nexport async function analyzeRoutes(\n routes: RouteInfo[],\n options: AnalyzeOptions,\n): Promise<PageAnalysis[]> {\n const results: PageAnalysis[] = [];\n for (const route of routes) {\n const analysis = await analyzePage(route, options);\n results.push(analysis);\n }\n return results;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { AuthConfig } from './types.js';\n\nconst MIDDLEWARE_FILES = ['middleware.ts', 'middleware.js', 'middleware.tsx', 'middleware.jsx'];\n\n/**\n * Extract cookie names from middleware source code.\n * Looks for patterns like: request.cookies.get('access_token')\n */\nfunction extractCookieNames(source: string): string[] {\n const cookies: string[] = [];\n const regex = /cookies\\.get\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n cookies.push(match[1]);\n }\n return [...new Set(cookies)];\n}\n\n/**\n * Extract API base URL from environment configuration.\n * Looks for NEXT_PUBLIC_API_URL or similar patterns.\n */\nfunction extractApiBaseUrl(source: string): string | null {\n const regex = /process\\.env\\.(\\w*API_URL\\w*)\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/;\n const match = source.match(regex);\n if (match) return match[2];\n\n const simpleRegex = /['\"]https?:\\/\\/[^'\"]+\\/api['\"]/;\n const simpleMatch = source.match(simpleRegex);\n if (simpleMatch) return simpleMatch[0].replace(/['\"]/g, '');\n\n return null;\n}\n\n/**\n * Extract auth check endpoint from source code.\n * Looks for patterns like: fetch(`${base}/auth/me`)\n */\nfunction extractAuthCheckEndpoint(source: string): string | null {\n const patterns = [\n /[`'\"](\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/auth\\/user)[`'\"]/,\n /[`'\"](\\/api\\/user\\/me)[`'\"]/,\n ];\n\n for (const pattern of patterns) {\n const match = source.match(pattern);\n if (match) return match[1];\n }\n\n return null;\n}\n\n/**\n * Detect authentication patterns in the target project.\n *\n * Scans for:\n * 1. middleware.ts/js with cookie checks\n * 2. Auth context providers with auth-check endpoints\n * 3. API base URL configuration\n */\nexport async function detectAuth(projectRoot: string, allSources: string[]): Promise<AuthConfig> {\n const config: AuthConfig = {\n hasAuth: false,\n cookieNames: [],\n authCheckEndpoint: null,\n apiBaseUrl: null,\n };\n\n // 1. Check for middleware\n for (const filename of MIDDLEWARE_FILES) {\n const middlewarePath = join(projectRoot, filename);\n if (existsSync(middlewarePath)) {\n try {\n const source = await readFile(middlewarePath, 'utf-8');\n const cookies = extractCookieNames(source);\n if (cookies.length > 0) {\n config.hasAuth = true;\n config.cookieNames.push(...cookies);\n }\n } catch {\n // Middleware exists but can't be read — skip\n }\n }\n }\n\n // 2. Scan all collected sources for auth patterns\n const combinedSource = allSources.join('\\n');\n\n const authEndpoint = extractAuthCheckEndpoint(combinedSource);\n if (authEndpoint) {\n config.hasAuth = true;\n config.authCheckEndpoint = authEndpoint;\n }\n\n // Look for auth context patterns\n if (/useAuth|AuthProvider|AuthContext|SessionProvider/i.test(combinedSource)) {\n config.hasAuth = true;\n }\n\n // 3. Extract API base URL\n config.apiBaseUrl = extractApiBaseUrl(combinedSource);\n\n return config;\n}\n","/**\n * A single mock response for an API endpoint.\n */\nexport interface MockResponse {\n /** HTTP status code */\n status: number;\n /** Response body as JSON-serializable data */\n body: unknown;\n /** Optional delay in milliseconds before responding */\n delay?: number;\n}\n\n/**\n * A complete mock configuration for rendering a page in a specific state.\n */\nexport interface MockConfig {\n /** State variant name (e.g., \"success\", \"error\", \"empty\", \"loading\") */\n stateName: string;\n /** Map of URL patterns to mock responses */\n apiMocks: Record<string, MockResponse>;\n /** Mock user data for auth, if auth is required */\n authMock: {\n /** Cookies to inject (e.g., { access_token: \"mock_token\" }) */\n cookies: Record<string, string>;\n /** Auth check endpoint mock response */\n authCheckResponse: MockResponse | null;\n } | null;\n /** Sample route parameters for dynamic routes */\n routeParams?: Record<string, string>;\n}\n\n/**\n * State variants to generate for each page.\n */\nexport type StateVariant = 'success' | 'empty' | 'error' | 'loading';\n\nexport const ALL_STATE_VARIANTS: StateVariant[] = ['success', 'empty', 'error', 'loading'];\n\n/**\n * Options for mock generation.\n */\nexport interface MockGeneratorOptions {\n /** Anthropic API key */\n apiKey: string;\n /** Model to use (default: claude-sonnet-4-20250514) */\n model?: string;\n /** State variants to generate (default: all) */\n variants?: StateVariant[];\n}\n","import Anthropic from '@anthropic-ai/sdk';\n\nexport interface LlmResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Simple LLM client wrapper for Anthropic Claude API.\n */\nexport class LlmClient {\n private client: Anthropic;\n private model: string;\n\n constructor(apiKey: string, model: string = 'claude-sonnet-4-20250514') {\n this.client = new Anthropic({ apiKey });\n this.model = model;\n }\n\n async generate(systemPrompt: string, userPrompt: string): Promise<LlmResponse> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n });\n\n const textBlock = response.content.find(block => block.type === 'text');\n const content = textBlock ? textBlock.text : '';\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n }\n}\n","import type { PageAnalysis } from '../analysis/types.js';\n\nexport const SYSTEM_PROMPT = `You are a mock data generator for a UI pre-rendering tool called VibeCanvas.\nYour job is to analyze a Next.js page's source code and generate realistic mock API responses that will make the page render correctly.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces found in the source code.\n3. Generate contextually appropriate data (e.g., real company names for a finance app, realistic usernames for a social app).\n4. For each API endpoint, generate mock responses for these state variants:\n - \"success\": realistic data with multiple items\n - \"empty\": empty collections, zero counts\n - \"error\": API returns HTTP 500 with error message\n - \"loading\": same as success but with a 3000ms delay\n5. Include auth mock data if the page requires authentication.\n6. For dynamic route parameters, generate a realistic sample value.`;\n\n/**\n * Build the user prompt for mock generation from a PageAnalysis.\n */\nexport function buildUserPrompt(analysis: PageAnalysis): string {\n const parts: string[] = [];\n\n parts.push(`## Page Route: ${analysis.route.urlPath}`);\n parts.push(`## Page File: ${analysis.route.filePath}`);\n\n if (analysis.route.isDynamic) {\n parts.push(`## Dynamic Parameters: ${analysis.route.params.map(p => p.name).join(', ')}`);\n }\n\n parts.push('## Source Code Context');\n parts.push(analysis.sourceContext);\n\n if (analysis.authConfig.hasAuth) {\n parts.push('## Auth Configuration');\n parts.push(`- Requires authentication: yes`);\n if (analysis.authConfig.cookieNames.length > 0) {\n parts.push(`- Auth cookies: ${analysis.authConfig.cookieNames.join(', ')}`);\n }\n if (analysis.authConfig.authCheckEndpoint) {\n parts.push(`- Auth check endpoint: ${analysis.authConfig.authCheckEndpoint}`);\n }\n if (analysis.authConfig.apiBaseUrl) {\n parts.push(`- API base URL: ${analysis.authConfig.apiBaseUrl}`);\n }\n }\n\n parts.push(`\n## Required Output Format\n\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" }, // only if dynamic route\n \"apiEndpoints\": [\n {\n \"urlPattern\": \"/api/endpoint\", // the URL path pattern to intercept\n \"method\": \"GET\", // HTTP method\n \"states\": {\n \"success\": { \"status\": 200, \"body\": { ... } },\n \"empty\": { \"status\": 200, \"body\": { ... } },\n \"error\": { \"status\": 500, \"body\": { \"detail\": \"Internal server error\" } },\n \"loading\": { \"status\": 200, \"body\": { ... }, \"delay\": 3000 }\n }\n }\n ],\n \"authMock\": { // only if auth is required\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nGenerate ONLY the JSON. No explanation, no markdown fences.`);\n\n return parts.join('\\n\\n');\n}\n","import type { PageAnalysis } from '../analysis/types.js';\nimport type { MockConfig, MockResponse, StateVariant, MockGeneratorOptions } from './types.js';\nimport { ALL_STATE_VARIANTS } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\ninterface LlmMockOutput {\n routeParams?: Record<string, string>;\n apiEndpoints?: Array<{\n urlPattern: string;\n method: string;\n states: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n // Strip markdown code fences if present\n let cleaned = content.trim();\n if (cleaned.startsWith('```')) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, '').replace(/\\n?```$/, '');\n }\n\n try {\n return JSON.parse(cleaned);\n } catch {\n // Try to find JSON object in the response\n const jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n }\n}\n\n/**\n * Convert LLM output into MockConfig[] (one per state variant).\n */\nfunction convertToMockConfigs(\n output: LlmMockOutput,\n analysis: PageAnalysis,\n variants: StateVariant[],\n): MockConfig[] {\n const configs: MockConfig[] = [];\n\n for (const variant of variants) {\n const apiMocks: Record<string, MockResponse> = {};\n\n if (output.apiEndpoints) {\n for (const endpoint of output.apiEndpoints) {\n const stateData = endpoint.states[variant];\n if (stateData) {\n const key = `${endpoint.method} ${endpoint.urlPattern}`;\n apiMocks[key] = {\n status: stateData.status,\n body: stateData.body,\n delay: stateData.delay,\n };\n }\n }\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n configs.push({\n stateName: variant,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n });\n }\n\n return configs;\n}\n\n/**\n * Generate a fallback MockConfig when LLM fails or page has no API deps.\n */\nfunction generateFallbackConfigs(\n analysis: PageAnalysis,\n variants: StateVariant[],\n): MockConfig[] {\n return variants.map(variant => ({\n stateName: variant,\n apiMocks: {},\n authMock: analysis.authConfig.hasAuth\n ? {\n cookies: Object.fromEntries(\n analysis.authConfig.cookieNames.map(name => [name, 'mock_token_c2d']),\n ),\n authCheckResponse: variant === 'error'\n ? { status: 401, body: { detail: 'Unauthorized' } }\n : { status: 200, body: { id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User' } },\n }\n : null,\n routeParams: analysis.route.isDynamic\n ? Object.fromEntries(analysis.route.params.map(p => [p.name, 'sample-1']))\n : undefined,\n }));\n}\n\n/**\n * Generate mock data for a single page using an LLM.\n *\n * Returns one MockConfig per requested state variant.\n * Falls back to empty mocks if:\n * - The page has no API dependencies\n * - LLM returns invalid data\n * - LLM call fails\n */\nexport async function generateMocks(\n analysis: PageAnalysis,\n options: MockGeneratorOptions,\n): Promise<{ configs: MockConfig[]; tokenUsage: { input: number; output: number } }> {\n const variants = options.variants ?? ALL_STATE_VARIANTS;\n\n // If no API dependencies, just return fallback configs (no LLM call needed)\n if (!analysis.hasApiDependencies) {\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n\n const client = new LlmClient(options.apiKey, options.model);\n const userPrompt = buildUserPrompt(analysis);\n\n try {\n const response = await client.generate(SYSTEM_PROMPT, userPrompt);\n const parsed = parseLlmJson(response.content);\n\n if (!parsed) {\n console.warn(`[c2d] Failed to parse LLM response for ${analysis.route.urlPath}, using fallback`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n }\n\n const configs = convertToMockConfigs(parsed, analysis, variants);\n\n return {\n configs,\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n } catch (error) {\n console.warn(`[c2d] LLM call failed for ${analysis.route.urlPath}: ${error}`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n}\n\n/**\n * Generate mocks for all analyzed pages.\n */\nexport async function generateAllMocks(\n analyses: PageAnalysis[],\n options: MockGeneratorOptions,\n): Promise<{\n results: Map<string, MockConfig[]>;\n totalTokens: { input: number; output: number };\n}> {\n const results = new Map<string, MockConfig[]>();\n const totalTokens = { input: 0, output: 0 };\n\n for (const analysis of analyses) {\n const { configs, tokenUsage } = await generateMocks(analysis, options);\n results.set(analysis.route.urlPath, configs);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n }\n\n return { results, totalTokens };\n}\n","import { chromium, type Browser, type BrowserContext, type Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { MockConfig, MockResponse } from '../mock/types.js';\nimport type { AuthConfig } from '../analysis/types.js';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type {\n RenderResult,\n RenderTask,\n RenderManifest,\n ManifestRoute,\n PreRenderOptions,\n ViewportConfig,\n} from './types.js';\nimport { startDevServer, type DevServerHandle } from './dev-server.js';\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_PAGE_TIMEOUT = 15000;\nconst DEFAULT_SETTLE_TIME = 1500;\nconst DEFAULT_VIEWPORT = { width: 1440, height: 900 };\n\n/**\n * Build the actual URL path for a route, substituting dynamic params.\n */\nfunction buildUrlPath(route: RouteInfo, mockConfig: MockConfig): string {\n let path = route.urlPath;\n if (route.isDynamic && mockConfig.routeParams) {\n for (const param of route.params) {\n const value = mockConfig.routeParams[param.name] || 'sample-1';\n path = path.replace(`:${param.name}`, value);\n // Also handle catch-all notation\n path = path.replace(`:${param.name}+`, value);\n path = path.replace(`:${param.name}*`, value);\n }\n }\n return path;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n * \"/\" → \"index\", \"/dashboard\" → \"dashboard\", \"/editor/:id\" → \"editor-_id\"\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Set up Playwright route interception for a page with the given mock config.\n */\nasync function setupMockInterception(\n page: Page,\n devServerUrl: string,\n mockConfig: MockConfig,\n authConfig: AuthConfig,\n): Promise<void> {\n // 1. Inject auth cookies if needed\n if (mockConfig.authMock) {\n const cookies = Object.entries(mockConfig.authMock.cookies).map(([name, value]) => ({\n name,\n value,\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n } else if (authConfig.hasAuth && authConfig.cookieNames.length > 0) {\n // Fallback: inject dummy cookies for detected auth\n const cookies = authConfig.cookieNames.map(name => ({\n name,\n value: 'c2d_mock_token',\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n }\n\n // 2. Build auth mock response for interception\n const authMockBody = mockConfig.authMock?.authCheckResponse\n ? JSON.stringify(mockConfig.authMock.authCheckResponse.body)\n : JSON.stringify({ id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User', email_verified: true, avatar_url: null, created_at: '2026-01-01T00:00:00Z' });\n\n // Common auth check URL patterns to always intercept\n const AUTH_PATTERNS = ['/auth/me', '/auth/session', '/api/auth/me', '/api/user/me', '/api/auth/session'];\n\n // 3. Intercept API calls\n await page.route('**/*', async (route) => {\n const request = route.request();\n const url = request.url();\n const method = request.method();\n\n // Always intercept auth check endpoints (common patterns + detected endpoint)\n const isAuthCheck = AUTH_PATTERNS.some(p => url.includes(p))\n || (authConfig.authCheckEndpoint && url.includes(authConfig.authCheckEndpoint));\n\n if (isAuthCheck) {\n const status = mockConfig.authMock?.authCheckResponse?.status ?? 200;\n return route.fulfill({\n status,\n contentType: 'application/json',\n body: authMockBody,\n });\n }\n\n // Check API mocks from AI-generated config\n for (const [pattern, mock] of Object.entries(mockConfig.apiMocks)) {\n // Pattern format: \"GET /api/reports\" or \"DELETE /api/reports/{id}\"\n const [mockMethod, ...pathParts] = pattern.split(' ');\n let mockPath = pathParts.join(' ');\n // Convert {param} placeholders to match any value\n mockPath = mockPath.replace(/\\{[^}]+\\}/g, '[^/]+');\n // Also handle * wildcards\n mockPath = mockPath.replace(/\\*/g, '[^/]+');\n\n const pathRegex = new RegExp(mockPath.replace(/\\//g, '\\\\/'));\n if (method === mockMethod && pathRegex.test(url)) {\n if (mock.delay) await new Promise(r => setTimeout(r, mock.delay));\n return route.fulfill({\n status: mock.status,\n contentType: 'application/json',\n body: JSON.stringify(mock.body),\n });\n }\n }\n\n // Pass through all other requests\n return route.continue();\n });\n}\n\n/**\n * Render a single page in a specific state and capture HTML + screenshot.\n */\nasync function renderPage(\n context: BrowserContext,\n devServerUrl: string,\n task: RenderTask,\n outputDir: string,\n options: { pageTimeout: number; settleTime: number },\n viewport?: ViewportConfig,\n): Promise<RenderResult> {\n const { route, mockConfig, authConfig } = task;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Include viewport name in file paths to avoid collisions when rendering multiple viewports\n const filePrefix = viewport ? `${mockConfig.stateName}_${viewport.name}` : mockConfig.stateName;\n const htmlRelPath = join('renders', routeSlug, `${filePrefix}.html`);\n const pngRelPath = join('renders', routeSlug, `${filePrefix}.png`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n const pngAbsPath = join(outputDir, pngRelPath);\n\n const page = await context.newPage();\n\n // Override viewport size for this page if a specific viewport was requested\n if (viewport) {\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n }\n\n try {\n await setupMockInterception(page, devServerUrl, mockConfig, authConfig);\n\n const urlPath = buildUrlPath(route, mockConfig);\n const fullUrl = `${devServerUrl}${urlPath}`;\n\n await page.goto(fullUrl, {\n waitUntil: 'networkidle',\n timeout: options.pageTimeout,\n });\n\n // Extra settle time for React hydration\n await page.waitForTimeout(options.settleTime);\n\n // Inline all external stylesheets so HTML is self-contained\n await page.evaluate(`(() => {\n const links = document.querySelectorAll('link[rel=\"stylesheet\"]');\n links.forEach(link => {\n try {\n const href = link.getAttribute('href');\n if (!href) return;\n for (const sheet of document.styleSheets) {\n if (sheet.href && sheet.href.includes(href.replace(/^\\\\//, ''))) {\n const rules = Array.from(sheet.cssRules).map(r => r.cssText).join('\\\\n');\n const style = document.createElement('style');\n style.textContent = rules;\n link.parentNode.replaceChild(style, link);\n break;\n }\n }\n } catch (e) {}\n });\n document.querySelectorAll('script').forEach(s => s.remove());\n })()`);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n // Capture screenshot\n await page.screenshot({ path: pngAbsPath, fullPage: true });\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\n };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n // Write an error placeholder HTML\n const errorHtml = `<!DOCTYPE html><html><body style=\"display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;color:#666;\">\n <div style=\"text-align:center\"><h2>Render Failed</h2><p>${route.urlPath} [${mockConfig.stateName}]</p><pre style=\"color:#c00\">${errorMsg}</pre></div>\n </body></html>`;\n await writeFile(htmlAbsPath, errorHtml, 'utf-8').catch(() => {});\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: false,\n error: errorMsg,\n viewportName: viewport?.name,\n };\n } finally {\n await page.close();\n }\n}\n\n/**\n * Process render tasks with limited concurrency.\n */\nasync function processWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<RenderResult>,\n onProgress?: (completed: number, total: number, result: RenderResult) => void,\n): Promise<RenderResult[]> {\n const results: RenderResult[] = [];\n const queue = [...items];\n const total = items.length;\n let completed = 0;\n\n async function worker() {\n while (queue.length > 0) {\n const item = queue.shift()!;\n const result = await fn(item);\n results.push(result);\n completed++;\n onProgress?.(completed, total, result);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * Build the render manifest from results.\n */\nfunction buildManifest(\n results: RenderResult[],\n projectName: string,\n viewports?: ViewportConfig[],\n): RenderManifest {\n const routeMap = new Map<string, ManifestRoute>();\n\n // Build a lookup for viewport widths by name\n const viewportWidthMap = new Map<string, number>();\n if (viewports) {\n for (const vp of viewports) {\n viewportWidthMap.set(vp.name, vp.width);\n }\n }\n\n for (const result of results) {\n const key = result.route.urlPath;\n if (!routeMap.has(key)) {\n routeMap.set(key, {\n urlPath: result.route.urlPath,\n filePath: result.route.filePath,\n states: [],\n });\n }\n routeMap.get(key)!.states.push({\n name: result.viewportName\n ? `${result.stateName} (${result.viewportName})`\n : result.stateName,\n htmlPath: result.htmlPath,\n screenshotPath: result.screenshotPath,\n status: result.success ? 'ok' : 'error',\n error: result.error,\n viewport: result.viewportName,\n viewportWidth: result.viewportName\n ? viewportWidthMap.get(result.viewportName)\n : undefined,\n });\n }\n\n return {\n generatedAt: new Date().toISOString(),\n projectName,\n routes: [...routeMap.values()].sort((a, b) => a.urlPath.localeCompare(b.urlPath)),\n };\n}\n\n/**\n * Pre-render all pages with their mock configurations.\n *\n * This is the main entry point for the rendering pipeline:\n * 1. Start dev server (or use provided URL)\n * 2. Launch Playwright browser\n * 3. For each (route, state) pair: intercept APIs, navigate, capture\n * 4. Write manifest.json\n * 5. Clean up\n */\nexport async function preRenderPages(\n tasks: RenderTask[],\n options: PreRenderOptions,\n): Promise<{ results: RenderResult[]; manifest: RenderManifest }> {\n const {\n projectRoot,\n outputDir = join(projectRoot, '.c2d'),\n concurrency = DEFAULT_CONCURRENCY,\n pageTimeout = DEFAULT_PAGE_TIMEOUT,\n settleTime = DEFAULT_SETTLE_TIME,\n viewportWidth = DEFAULT_VIEWPORT.width,\n viewportHeight = DEFAULT_VIEWPORT.height,\n } = options;\n\n // Resolve viewports: if explicit viewports array is provided use it,\n // otherwise fall back to the single viewport from viewportWidth/Height\n // (which themselves default to 1440x900).\n const viewports: ViewportConfig[] | undefined = options.viewports;\n const useMultiViewport = viewports && viewports.length > 0;\n\n // Create output directory\n await mkdir(outputDir, { recursive: true });\n\n // Start dev server\n let devServer: DevServerHandle | null = null;\n try {\n devServer = await startDevServer(projectRoot, {\n port: options.devServerPort,\n devServerUrl: options.devServerUrl,\n });\n\n // Launch browser\n const browser = await chromium.launch({ headless: true });\n const context = await browser.newContext({\n viewport: { width: viewportWidth, height: viewportHeight },\n });\n\n try {\n let results: RenderResult[];\n\n if (useMultiViewport) {\n // Expand tasks: each original task is rendered at each viewport\n const expandedItems: Array<{ task: RenderTask; viewport: ViewportConfig }> = [];\n for (const task of tasks) {\n for (const vp of viewports) {\n expandedItems.push({ task, viewport: vp });\n }\n }\n\n results = await processWithConcurrency(\n expandedItems,\n concurrency,\n ({ task, viewport: vp }) =>\n renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime }, vp),\n options.onProgress,\n );\n } else {\n // Single viewport — backward-compatible path (no viewportName in results)\n results = await processWithConcurrency(\n tasks,\n concurrency,\n (task) => renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime }),\n options.onProgress,\n );\n }\n\n // Read project name from package.json\n let projectName = 'unknown';\n try {\n const pkg = await import(join(projectRoot, 'package.json'), { with: { type: 'json' } });\n projectName = pkg.default?.name || 'unknown';\n } catch {\n // Can't read package.json — use fallback\n }\n\n // Build and write manifest\n const manifest = buildManifest(\n results,\n projectName,\n useMultiViewport ? viewports : undefined,\n );\n await writeFile(\n join(outputDir, 'manifest.json'),\n JSON.stringify(manifest, null, 2),\n 'utf-8',\n );\n\n return { results, manifest };\n } finally {\n await context.close();\n await browser.close();\n }\n } finally {\n if (devServer) {\n await devServer.stop();\n }\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createServer } from 'node:net';\n\n/**\n * Find a free port on the system.\n */\nexport async function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.listen(0, () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not find free port')));\n }\n });\n server.on('error', reject);\n });\n}\n\n/**\n * Wait for a URL to become reachable.\n */\nasync function waitForUrl(url: string, timeoutMs: number = 30000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(2000) });\n // Any response (even redirects) means the server is up\n if (response.status > 0) return;\n } catch {\n // Server not ready yet\n }\n await new Promise(r => setTimeout(r, 500));\n }\n throw new Error(`Dev server did not become ready at ${url} within ${timeoutMs}ms`);\n}\n\n/**\n * Detect the dev command for a project.\n */\nfunction detectDevCommand(projectRoot: string): { cmd: string; args: string[] } {\n if (existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'))) {\n return { cmd: 'npx', args: ['next', 'dev'] };\n }\n // Fallback to npm run dev\n return { cmd: 'npm', args: ['run', 'dev'] };\n}\n\nexport interface DevServerHandle {\n url: string;\n port: number;\n process: ChildProcess | null;\n stop: () => Promise<void>;\n}\n\n/**\n * Start a dev server for the target project.\n *\n * If devServerUrl is provided, uses that instead of starting a new server.\n */\nexport async function startDevServer(\n projectRoot: string,\n options?: { port?: number; devServerUrl?: string },\n): Promise<DevServerHandle> {\n // If a URL is provided, use it directly (user has server running)\n if (options?.devServerUrl) {\n await waitForUrl(options.devServerUrl, 10000);\n return {\n url: options.devServerUrl,\n port: 0,\n process: null,\n stop: async () => {},\n };\n }\n\n const port = options?.port ?? await findFreePort();\n const { cmd, args } = detectDevCommand(projectRoot);\n const fullArgs = [...args, '--port', String(port)];\n\n const child = spawn(cmd, fullArgs, {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, PORT: String(port) },\n });\n\n const url = `http://localhost:${port}`;\n\n // Collect stderr for error reporting\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n // Handle early exit\n const exitPromise = new Promise<never>((_, reject) => {\n child.on('exit', (code) => {\n if (code !== null && code !== 0) {\n reject(new Error(`Dev server exited with code ${code}.\\n${stderr.slice(-500)}`));\n }\n });\n });\n\n // Wait for server to be ready or fail\n try {\n await Promise.race([\n waitForUrl(url, 60000),\n exitPromise,\n ]);\n } catch (err) {\n child.kill('SIGTERM');\n throw err;\n }\n\n return {\n url,\n port,\n process: child,\n stop: async () => {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n resolve();\n }, 5000);\n child.on('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n },\n };\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport sirv from 'sirv';\nimport { handleApiRequest } from './api-routes.js';\n\n/**\n * Options for starting the canvas server.\n */\nexport interface CanvasServerOptions {\n /** Port to listen on (default: 4800) */\n port: number;\n /** Path to the built canvas app directory */\n canvasDir: string;\n /** Path to the .c2d/ output directory */\n c2dDir: string;\n /** Path to the target project root (for serving public/ assets) */\n projectRoot?: string;\n}\n\nconst MAX_PORT_ATTEMPTS = 10;\n\n/**\n * Try to listen on a port. Returns a promise that resolves on success\n * or rejects with the error.\n */\nfunction tryListen(\n requestHandler: (req: IncomingMessage, res: ServerResponse) => void,\n port: number,\n): Promise<{ url: string; port: number; close: () => Promise<void> }> {\n return new Promise((resolve, reject) => {\n const server = createServer(requestHandler);\n server.once('error', reject);\n server.listen(port, () => {\n const actualPort = (server.address() as { port: number }).port;\n resolve({\n url: `http://localhost:${actualPort}`,\n port: actualPort,\n close: () =>\n new Promise<void>((resolveClose, rejectClose) => {\n server.close((err) => {\n if (err) rejectClose(err);\n else resolveClose();\n });\n }),\n });\n });\n });\n}\n\n/**\n * Start the canvas server that serves:\n * 1. API endpoints under /api/\n * 2. Pre-rendered files from .c2d/renders/ under /renders/\n * 3. Canvas app static assets (SPA fallback) for everything else\n *\n * If the default port is in use, tries up to 10 consecutive ports.\n */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir, projectRoot } = options;\n\n // Static file handlers\n const canvasHandler = sirv(canvasDir, { single: true, dev: true });\n const rendersDir = join(c2dDir, 'renders');\n const rendersHandler = sirv(rendersDir, { dev: true });\n\n // Serve target project's public/ folder for static assets (images, fonts, etc.)\n const publicDir = projectRoot ? join(projectRoot, 'public') : null;\n const publicHandler = publicDir && existsSync(publicDir)\n ? sirv(publicDir, { dev: true })\n : null;\n\n // Request handler\n const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n // CORS headers on all responses\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n // API routes\n if (url.startsWith('/api/')) {\n try {\n const handled = await handleApiRequest(req, res, c2dDir);\n if (!handled) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal server error';\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: message }));\n }\n return;\n }\n\n // Renders (pre-rendered HTML/screenshots)\n if (url.startsWith('/renders/')) {\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\n });\n return;\n }\n\n // Try project's public/ folder (images, fonts, icons, etc.)\n if (publicHandler) {\n publicHandler(req, res, () => {\n // Not found in public/ — fall through to canvas SPA\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n });\n return;\n }\n\n // Canvas app (SPA with fallback to index.html)\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n };\n\n // Try ports starting from the configured port\n for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {\n const tryPort = port + attempt;\n try {\n return await tryListen(requestHandler, tryPort);\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < MAX_PORT_ATTEMPTS - 1) {\n continue;\n }\n throw err;\n }\n }\n\n throw new Error(`Could not find an available port (tried ${port}-${port + MAX_PORT_ATTEMPTS - 1})`);\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/**\n * A single pen stroke on the drawing canvas.\n */\nexport interface DrawingStroke {\n points: { x: number; y: number }[];\n color: string;\n width: number;\n}\n\n/**\n * A comment pinned to a canvas coordinate.\n */\nexport interface Comment {\n id: string;\n x: number;\n y: number;\n text: string;\n author: string;\n timestamp: string;\n}\n\n/**\n * Handle API requests under the /api/ prefix.\n *\n * Returns true if the request was handled, false otherwise.\n */\nexport async function handleApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<boolean> {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n if (url === '/api/manifest' && method === 'GET') {\n await handleGetManifest(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'GET') {\n await handleGetComments(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'POST') {\n await handlePostComment(req, res, c2dDir);\n return true;\n }\n\n const deleteMatch = url.match(/^\\/api\\/comments\\/(.+)$/);\n if (deleteMatch && method === 'DELETE') {\n await handleDeleteComment(res, c2dDir, deleteMatch[1]);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'GET') {\n await handleGetDrawings(res, c2dDir);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'POST') {\n await handlePostDrawings(req, res, c2dDir);\n return true;\n }\n\n return false;\n}\n\n// --- Handlers ---\n\nasync function handleGetManifest(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const manifestPath = join(c2dDir, 'manifest.json');\n if (!existsSync(manifestPath)) {\n sendJson(res, 404, { error: 'manifest.json not found' });\n return;\n }\n const data = await readFile(manifestPath, 'utf-8');\n sendRawJson(res, 200, data);\n}\n\nasync function handleGetComments(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n sendJson(res, 200, comments);\n}\n\nasync function handlePostComment(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!isValidCommentInput(parsed)) {\n sendJson(res, 400, { error: 'Missing required fields: x, y, text, author' });\n return;\n }\n\n const comment: Comment = {\n id: randomUUID(),\n x: parsed.x,\n y: parsed.y,\n text: parsed.text,\n author: parsed.author,\n timestamp: new Date().toISOString(),\n };\n\n const comments = await loadComments(c2dDir);\n comments.push(comment);\n await saveComments(c2dDir, comments);\n sendJson(res, 201, comment);\n}\n\nasync function handleDeleteComment(\n res: ServerResponse,\n c2dDir: string,\n id: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n const index = comments.findIndex(c => c.id === id);\n if (index === -1) {\n sendJson(res, 404, { error: 'Comment not found' });\n return;\n }\n comments.splice(index, 1);\n await saveComments(c2dDir, comments);\n sendJson(res, 200, { ok: true });\n}\n\n// --- Drawing Handlers ---\n\nasync function handleGetDrawings(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const drawings = await loadDrawings(c2dDir);\n sendJson(res, 200, drawings);\n}\n\nasync function handlePostDrawings(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!Array.isArray(parsed)) {\n sendJson(res, 400, { error: 'Body must be an array of strokes' });\n return;\n }\n\n await saveDrawings(c2dDir, parsed as DrawingStroke[]);\n sendJson(res, 200, { ok: true });\n}\n\nasync function loadDrawings(c2dDir: string): Promise<DrawingStroke[]> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n if (!existsSync(drawingsPath)) {\n return [];\n }\n const data = await readFile(drawingsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveDrawings(c2dDir: string, drawings: DrawingStroke[]): Promise<void> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n const dir = dirname(drawingsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(drawingsPath, JSON.stringify(drawings, null, 2), 'utf-8');\n}\n\n// --- Helpers ---\n\nfunction isValidCommentInput(\n value: unknown,\n): value is { x: number; y: number; text: string; author: string } {\n if (typeof value !== 'object' || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.x === 'number' &&\n typeof obj.y === 'number' &&\n typeof obj.text === 'string' &&\n typeof obj.author === 'string'\n );\n}\n\nasync function loadComments(c2dDir: string): Promise<Comment[]> {\n const commentsPath = join(c2dDir, 'comments.json');\n if (!existsSync(commentsPath)) {\n return [];\n }\n const data = await readFile(commentsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveComments(c2dDir: string, comments: Comment[]): Promise<void> {\n const commentsPath = join(c2dDir, 'comments.json');\n const dir = dirname(commentsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(commentsPath, JSON.stringify(comments, null, 2), 'utf-8');\n}\n\nfunction readRequestBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n req.on('error', reject);\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(body);\n}\n\nfunction sendRawJson(res: ServerResponse, status: number, jsonString: string): void {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(jsonString);\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface VibeCanvasConfig {\n apiKey: string;\n port: number;\n excludeRoutes: string[];\n devServerUrl?: string;\n devServerCommand?: string;\n}\n\nconst DEFAULT_PORT = 4800;\n\n/**\n * Load configuration from environment variables and optional config file.\n */\nexport async function loadConfig(projectRoot: string): Promise<VibeCanvasConfig> {\n let fileConfig: Partial<VibeCanvasConfig> = {};\n\n // Try to load c2d.config.js\n const configPath = join(projectRoot, 'c2d.config.js');\n if (existsSync(configPath)) {\n try {\n const mod = await import(configPath);\n fileConfig = mod.default || mod;\n } catch {\n // Config file exists but can't be loaded — use defaults\n }\n }\n\n const apiKey = process.env.C2D_API_KEY || fileConfig.apiKey || '';\n\n return {\n apiKey,\n port: fileConfig.port || Number(process.env.C2D_PORT) || DEFAULT_PORT,\n excludeRoutes: fileConfig.excludeRoutes || [],\n devServerUrl: fileConfig.devServerUrl || process.env.C2D_DEV_SERVER_URL,\n devServerCommand: fileConfig.devServerCommand,\n };\n}\n\n/**\n * Detect if the current directory is a Next.js App Router project.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\n const hasNextConfig =\n existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'));\n\n // Check both app/ and src/app/ (common Next.js structures)\n let appDir = join(projectRoot, 'app');\n let hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'app');\n hasAppDir = existsSync(appDir);\n }\n\n let projectName = 'unknown';\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n projectName = pkg.name || 'unknown';\n } catch {\n // No package.json\n }\n\n return {\n isNextJs: hasNextConfig,\n appDir: hasAppDir ? appDir : null,\n projectName,\n };\n}\n","/**\n * Simple console progress utilities for the CLI.\n */\n\nconst COLORS = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n};\n\nexport function log(message: string): void {\n console.log(`${COLORS.dim}[c2d]${COLORS.reset} ${message}`);\n}\n\nexport function success(message: string): void {\n console.log(`${COLORS.green} ✓${COLORS.reset} ${message}`);\n}\n\nexport function warn(message: string): void {\n console.log(`${COLORS.yellow} ⚠${COLORS.reset} ${message}`);\n}\n\nexport function error(message: string): void {\n console.error(`${COLORS.red} ✗${COLORS.reset} ${message}`);\n}\n\nexport function header(message: string): void {\n console.log(`\\n${COLORS.bold}${COLORS.cyan}${message}${COLORS.reset}`);\n}\n\nexport function step(current: number, total: number, message: string): void {\n console.log(`${COLORS.dim} [${current}/${total}]${COLORS.reset} ${message}`);\n}\n\nexport function banner(): void {\n console.log(`\n${COLORS.bold}${COLORS.cyan} Code to Design${COLORS.reset} ${COLORS.dim}v0.1.0${COLORS.reset}\n${COLORS.dim} AI-powered UI review canvas${COLORS.reset}\n`);\n}\n"],"mappings":"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","names":["join","mkdir","existsSync","readFile","join","existsSync","join","join","existsSync","readFile","error","join","existsSync","join","resolve","join","createServer","join","existsSync","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","resolve","createServer","join","existsSync","existsSync","readFile","join","join","existsSync","mkdir","r","resolve","dirname","writeFile"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runScan
3
- } from "../chunk-BHEMO5RW.js";
3
+ } from "../chunk-WX4KLWOS.js";
4
4
  export {
5
5
  runScan
6
6
  };
package/dist/index.d.ts CHANGED
@@ -12,6 +12,8 @@ interface CanvasServerOptions {
12
12
  canvasDir: string;
13
13
  /** Path to the .c2d/ output directory */
14
14
  c2dDir: string;
15
+ /** Path to the target project root (for serving public/ assets) */
16
+ projectRoot?: string;
15
17
  }
16
18
  /**
17
19
  * Start the canvas server that serves:
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  loadConfig,
4
4
  runScan,
5
5
  startCanvasServer
6
- } from "./chunk-BHEMO5RW.js";
6
+ } from "./chunk-WX4KLWOS.js";
7
7
 
8
8
  // src/version.ts
9
9
  var version = "0.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-to-design",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "AI-powered UI review canvas — CLI tool",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/scan.ts","../../core/src/discovery/route-scanner.ts","../../core/src/analysis/code-analyzer.ts","../../core/src/analysis/auth-detector.ts","../../core/src/mock/types.ts","../../core/src/mock/llm-client.ts","../../core/src/mock/prompt-templates.ts","../../core/src/mock/mock-generator.ts","../../core/src/render/pre-renderer.ts","../../core/src/render/dev-server.ts","../src/server/canvas-server.ts","../src/server/api-routes.ts","../src/config.ts","../src/utils/progress.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { rm, mkdir } from 'node:fs/promises';\nimport { existsSync, watch as fsWatch } from 'node:fs';\nimport {\n scanRoutes,\n analyzePage,\n generateMocks,\n preRenderPages,\n type RenderTask,\n type MockGeneratorOptions,\n} from '@code-to-design/core';\nimport { startCanvasServer } from '../server/canvas-server.js';\nimport { loadConfig, detectNextJsProject } from '../config.js';\nimport * as ui from '../utils/progress.js';\n\n/**\n * Main scan command — runs the full Code to Design pipeline.\n *\n * 1. Detect project type\n * 2. Discover routes\n * 3. Analyze code + generate mocks\n * 4. Pre-render pages\n * 5. Start canvas server\n */\nexport async function runScan(options: {\n projectRoot: string;\n skipRender?: boolean;\n open?: boolean;\n watch?: boolean;\n}): Promise<void> {\n const { projectRoot, skipRender = false, open = true, watch = false } = options;\n\n ui.banner();\n\n // Load config\n const config = await loadConfig(projectRoot);\n\n // Step 1: Detect project\n ui.header('Detecting project...');\n const project = await detectNextJsProject(projectRoot);\n\n if (!project.isNextJs) {\n ui.error('Not a Next.js project (no next.config.ts/js/mjs found).');\n ui.log('Code to Design currently supports Next.js App Router projects only.');\n process.exit(1);\n }\n\n if (!project.appDir) {\n ui.error('No app/ directory found. Code to Design requires Next.js App Router.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName}`);\n ui.success(`App directory: ${project.appDir}`);\n\n const c2dDir = join(projectRoot, '.c2d');\n\n // If --skip-render, just start the server with existing renders\n if (skipRender) {\n if (!existsSync(join(c2dDir, 'manifest.json'))) {\n ui.error('No previous renders found. Run without --skip-render first.');\n process.exit(1);\n }\n ui.log('Skipping render, using existing canvas data...');\n await startServer(c2dDir, config.port, open);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const routes = await scanRoutes({ appDir: project.appDir });\n\n if (routes.length === 0) {\n ui.error('No routes found in app/ directory.');\n process.exit(1);\n }\n\n // Filter excluded routes\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n ui.success(`Found ${filteredRoutes.length} routes`);\n for (const r of filteredRoutes) {\n ui.log(` ${r.urlPath}${r.isDynamic ? ' [dynamic]' : ''}`);\n }\n\n // Step 3: Check API key\n if (!config.apiKey) {\n ui.warn('No API key configured. Mock generation will use fallback data.');\n ui.log('Set C2D_API_KEY env var or add apiKey to c2d.config.js');\n }\n\n // Step 4: Analyze and generate mocks\n ui.header('Analyzing code and generating mocks...');\n\n const renderTasks: RenderTask[] = [];\n let totalTokens = { input: 0, output: 0 };\n\n const mockOptions: MockGeneratorOptions = {\n apiKey: config.apiKey,\n };\n\n for (let i = 0; i < filteredRoutes.length; i++) {\n const route = filteredRoutes[i];\n ui.step(i + 1, filteredRoutes.length, `${route.urlPath}`);\n\n // Analyze page\n const analysis = await analyzePage(route, { projectRoot });\n\n // Generate mocks\n const { configs, tokenUsage } = await generateMocks(analysis, mockOptions);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n\n // Create render tasks\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n if (totalTokens.input > 0) {\n ui.success(`Mock generation complete (${totalTokens.input} input tokens, ${totalTokens.output} output tokens)`);\n } else {\n ui.success('Using fallback mocks (no API key or no API dependencies)');\n }\n\n // Step 5: Pre-render\n ui.header(`Pre-rendering ${renderTasks.length} page states...`);\n\n // Clear previous renders but preserve comments\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n const { results, manifest } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n onProgress: (completed, total, result) => {\n const pct = Math.round((completed / total) * 100);\n const icon = result.success ? '✓' : '✗';\n const label = `${result.route.urlPath} [${result.stateName}]`;\n process.stdout.write(`\\r ${icon} ${completed}/${total} (${pct}%) ${label}${''.padEnd(20)}`);\n if (completed === total) process.stdout.write('\\n');\n },\n });\n\n const successCount = results.filter((r) => r.success).length;\n const failCount = results.filter((r) => !r.success).length;\n\n ui.success(`Rendered ${successCount}/${results.length} pages`);\n if (failCount > 0) {\n ui.warn(`${failCount} pages failed to render`);\n for (const r of results.filter((r) => !r.success)) {\n ui.error(` ${r.route.urlPath} [${r.stateName}]: ${r.error}`);\n }\n }\n\n // Step 6: Start canvas server\n if (watch) {\n // In watch mode, start the server without blocking so we can watch for changes\n const server = await startServerNonBlocking(c2dDir, config.port, open);\n watchAndRerender(projectRoot, project.appDir!, c2dDir, config);\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n } else {\n await startServer(c2dDir, config.port, open);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean): Promise<void> {\n ui.header('Starting canvas server...');\n\n // Resolve canvas app directory: find canvas-dist relative to this package\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir,\n c2dDir,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Press Ctrl+C to stop\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n}\n\nasync function startServerNonBlocking(\n c2dDir: string,\n port: number,\n open: boolean,\n): Promise<{ url: string; close: () => Promise<void> }> {\n ui.header('Starting canvas server...');\n\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir: canvasDir!,\n c2dDir,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Watching for file changes...\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n return server;\n}\n\n/**\n * Find the canvas-dist directory by walking up from the module's location\n * until we find a directory containing canvas-dist/.\n * Works in both npm-installed and monorepo-dev environments.\n */\nasync function resolveCanvasDir(c2dDir: string): Promise<string> {\n const { fileURLToPath } = await import('node:url');\n const { dirname } = await import('node:path');\n const __filename = fileURLToPath(import.meta.url);\n\n // Walk up from the current file's directory to find canvas-dist/\n let dir = dirname(__filename);\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, 'canvas-dist');\n if (existsSync(candidate) && existsSync(join(candidate, 'index.html'))) {\n return candidate;\n }\n dir = dirname(dir);\n }\n\n // Fallback: try monorepo dev location\n const monorepoDev = join(dirname(__filename), '..', '..', '..', '..', 'apps', 'canvas', 'dist');\n if (existsSync(monorepoDev) && existsSync(join(monorepoDev, 'index.html'))) {\n return monorepoDev;\n }\n\n // Last resort: write placeholder\n const placeholder = join(c2dDir, '_canvas');\n await mkdir(placeholder, { recursive: true });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(join(placeholder, 'index.html'), `<!DOCTYPE html><html><body>\n <h1>Code to Design</h1>\n <p>Canvas app not built. Run: <code>cd apps/canvas && npx vite build</code></p>\n <p><a href=\"/api/manifest\">View Manifest</a></p>\n </body></html>`);\n return placeholder;\n}\n\n/** File extensions to watch for changes. */\nconst WATCH_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.css']);\n\n/** Directories and patterns to ignore during watch. */\nfunction shouldIgnoreFile(filename: string | null): boolean {\n if (!filename) return true;\n const ignored = ['node_modules', '.next', '.c2d', '.git'];\n if (ignored.some((dir) => filename.includes(dir))) return true;\n const ext = filename.slice(filename.lastIndexOf('.'));\n return !WATCH_EXTENSIONS.has(ext);\n}\n\nfunction watchAndRerender(\n projectRoot: string,\n appDir: string,\n c2dDir: string,\n config: Awaited<ReturnType<typeof loadConfig>>,\n): void {\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n let isRendering = false;\n\n ui.log(`Watching ${appDir} for changes...`);\n\n fsWatch(appDir, { recursive: true }, (_event, filename) => {\n if (shouldIgnoreFile(filename as string | null)) return;\n\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (isRendering) return;\n isRendering = true;\n\n ui.log(`\\nFile changed: ${filename}. Re-rendering...`);\n\n try {\n // Re-discover routes\n const routes = await scanRoutes({ appDir });\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n // Re-analyze and generate mocks\n const renderTasks: RenderTask[] = [];\n const mockOptions: MockGeneratorOptions = { apiKey: config.apiKey };\n\n for (const route of filteredRoutes) {\n const analysis = await analyzePage(route, { projectRoot });\n const { configs } = await generateMocks(analysis, mockOptions);\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n // Clear previous renders\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n // Pre-render\n const { results } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n });\n\n const successCount = results.filter((r) => r.success).length;\n ui.success(`Re-render complete. ${successCount} pages updated.`);\n } catch (err: any) {\n ui.error(`Re-render failed: ${err.message || err}`);\n } finally {\n isRendering = false;\n }\n }, 500);\n });\n}\n","import { readdir, stat } from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport { RouteInfo, RouteParam, ScanOptions } from './types.js';\n\nconst PAGE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx']);\nconst PAGE_BASENAMES = new Set(['page']);\n\n/**\n * Check if a filename is a page file (page.tsx, page.js, etc.)\n */\nfunction isPageFile(filename: string): boolean {\n const ext = extname(filename);\n const basename = filename.slice(0, -ext.length);\n return PAGE_EXTENSIONS.has(ext) && PAGE_BASENAMES.has(basename);\n}\n\n/**\n * Check if a directory should be skipped entirely.\n */\nfunction shouldSkipDir(name: string): boolean {\n // Private folders\n if (name.startsWith('_')) return true;\n // Parallel route slots\n if (name.startsWith('@')) return true;\n // Intercepting routes\n if (name.startsWith('(.)') || name.startsWith('(..)')) return true;\n // Build artifacts and dependencies\n if (name === 'node_modules' || name === '.next') return true;\n return false;\n}\n\n/**\n * Check if a directory is a route group (parenthesized name like \"(auth)\").\n * Route groups are stripped from the URL but recursed into.\n */\nfunction isRouteGroup(name: string): boolean {\n return name.startsWith('(') && name.endsWith(')') && !name.startsWith('(.');\n}\n\n/**\n * Parse a dynamic route segment and extract parameter info.\n * Returns null if the segment is not dynamic.\n */\nfunction parseDynamicSegment(segment: string): RouteParam | null {\n // Optional catch-all: [[...param]]\n const optionalCatchAll = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n if (optionalCatchAll) {\n return { name: optionalCatchAll[1], isCatchAll: true, isOptional: true };\n }\n\n // Required catch-all: [...param]\n const catchAll = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n if (catchAll) {\n return { name: catchAll[1], isCatchAll: true, isOptional: false };\n }\n\n // Single dynamic: [param]\n const dynamic = segment.match(/^\\[(.+)\\]$/);\n if (dynamic) {\n return { name: dynamic[1], isCatchAll: false, isOptional: false };\n }\n\n return null;\n}\n\n/**\n * Convert a dynamic segment to a URL-friendly representation.\n */\nfunction segmentToUrlPart(segment: string): string {\n const param = parseDynamicSegment(segment);\n if (!param) return segment;\n\n if (param.isCatchAll && param.isOptional) return `:${param.name}*`;\n if (param.isCatchAll) return `:${param.name}+`;\n return `:${param.name}`;\n}\n\n/**\n * Recursively scan a directory for Next.js App Router page files.\n */\nasync function scanDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPageFile(entry)) {\n const urlPath = '/' + urlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...params],\n isDynamic: params.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n if (shouldSkipDir(entry)) continue;\n\n if (isRouteGroup(entry)) {\n // Route groups: recurse but don't add to URL\n const nested = await scanDir(entryPath, urlSegments, params);\n routes.push(...nested);\n } else {\n // Regular or dynamic segment\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n }\n\n return routes;\n}\n\n/**\n * Scan a Next.js App Router `app/` directory and extract all renderable routes.\n *\n * Follows Next.js conventions:\n * - page.{js,jsx,ts,tsx} files define renderable routes\n * - Route groups (name) are stripped from URLs\n * - Private folders _name are skipped\n * - Parallel routes @slot are skipped\n * - Intercepting routes (.) are skipped\n * - Dynamic routes [param] are included with parameter metadata\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir } = options;\n\n const dirStat = await stat(appDir).catch(() => null);\n if (!dirStat || !dirStat.isDirectory()) {\n throw new Error(`App directory not found: ${appDir}`);\n }\n\n const routes = await scanDir(appDir, [], []);\n\n // Sort routes for consistent output\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n\n return routes;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join, dirname, resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type { PageAnalysis, AnalyzeOptions } from './types.js';\nimport { detectAuth } from './auth-detector.js';\n\nconst DEFAULT_MAX_TOKENS = 8000;\nconst CHARS_PER_TOKEN = 4; // rough approximation\n\n/**\n * Extract import paths from TypeScript/JavaScript source code.\n * Uses regex — does not handle barrel exports or re-exports.\n */\nfunction extractImportPaths(source: string): string[] {\n const paths: string[] = [];\n // Match: import ... from '...' and import '...'\n const regex = /import\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n paths.push(match[1]);\n }\n return paths;\n}\n\n/**\n * Resolve tsconfig path aliases (e.g., @/lib/api → /absolute/path/lib/api).\n * Returns an absolute path when aliases contain absolute base paths.\n */\nfunction resolvePathAlias(\n importPath: string,\n aliases: Record<string, string>,\n): string | null {\n for (const [pattern, replacement] of Object.entries(aliases)) {\n const prefix = pattern.replace(/\\*$/, '');\n if (importPath.startsWith(prefix)) {\n const rest = importPath.slice(prefix.length);\n return replacement.replace(/\\*$/, '') + rest;\n }\n }\n return null;\n}\n\n/**\n * Read tsconfig.json and extract path aliases.\n */\nasync function readPathAliases(projectRoot: string): Promise<Record<string, string>> {\n const aliases: Record<string, string> = {};\n\n for (const filename of ['tsconfig.json', 'jsconfig.json']) {\n const configPath = join(projectRoot, filename);\n if (!existsSync(configPath)) continue;\n\n try {\n const content = await readFile(configPath, 'utf-8');\n // Strip JSON5-style comments while preserving // inside strings.\n // Match strings first (to skip them), then line & block comments.\n const stripped = content.replace(\n /\"(?:[^\"\\\\]|\\\\.)*\"|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm,\n (match) => (match.startsWith('\"') ? match : ''),\n );\n const config = JSON.parse(stripped);\n const paths = config.compilerOptions?.paths;\n const baseUrl = config.compilerOptions?.baseUrl || '.';\n const resolvedBaseUrl = resolve(projectRoot, baseUrl);\n\n if (paths) {\n for (const [key, values] of Object.entries(paths)) {\n const targets = values as string[];\n if (targets.length > 0) {\n // Store as absolute path for reliable resolution\n aliases[key] = join(resolvedBaseUrl, targets[0]);\n }\n }\n }\n } catch {\n // Can't parse tsconfig — skip aliases\n }\n }\n\n return aliases;\n}\n\n/**\n * Try to resolve an import path to an actual file.\n */\nfunction resolveImportToFile(importPath: string, fromDir: string): string | null {\n // Try exact path first, then with extensions\n const extensions = ['.ts', '.tsx', '.js', '.jsx'];\n const candidates: string[] = [];\n\n const resolved = resolve(fromDir, importPath);\n\n // Try exact\n candidates.push(resolved);\n // Try with extensions\n for (const ext of extensions) {\n candidates.push(resolved + ext);\n }\n // Try as directory with index\n for (const ext of extensions) {\n candidates.push(join(resolved, `index${ext}`));\n }\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Trace imports from a source file, up to maxDepth levels deep.\n * Returns a map of filePath → source content.\n */\nasync function traceImports(\n filePath: string,\n projectRoot: string,\n aliases: Record<string, string>,\n maxDepth: number,\n visited: Set<string> = new Set(),\n): Promise<Map<string, string>> {\n const results = new Map<string, string>();\n\n if (visited.has(filePath) || maxDepth < 0) return results;\n visited.add(filePath);\n\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n return results;\n }\n\n results.set(filePath, source);\n\n const importPaths = extractImportPaths(source);\n const fileDir = dirname(filePath);\n\n for (const importPath of importPaths) {\n // Skip node_modules imports\n if (!importPath.startsWith('.') && !importPath.startsWith('@/') && !importPath.startsWith('~/')) {\n // Check if it's a path alias\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (!aliasResolved) continue;\n\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else if (importPath.startsWith('.')) {\n // Relative import\n const resolved = resolveImportToFile(importPath, fileDir);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else {\n // Path alias (e.g., @/lib/api-client)\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (aliasResolved) {\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Estimate token count from a string (rough: ~4 chars per token).\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\n/**\n * Check if source code contains API call patterns.\n */\nfunction hasApiCalls(source: string): boolean {\n return /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\buseQuery\\b/.test(source)\n || /\\buseMutation\\b/.test(source)\n || /\\bapiRequest\\b/.test(source)\n || /\\bgetServerSideProps\\b/.test(source)\n || /\\bgetStaticProps\\b/.test(source)\n || /API_BASE_URL/.test(source)\n || /['\"]\\/api\\//.test(source)\n // Detect imports from api/client modules (common naming patterns)\n || /from\\s+['\"].*api[-_]?client.*['\"]/.test(source)\n || /from\\s+['\"].*\\/api['\"]/.test(source)\n || /from\\s+['\"].*\\/services\\//.test(source);\n}\n\n/**\n * Analyze a single page: read its source, trace imports, detect auth,\n * and produce a context string suitable for LLM mock generation.\n */\nexport async function analyzePage(\n route: RouteInfo,\n options: AnalyzeOptions,\n): Promise<PageAnalysis> {\n const { projectRoot, maxTokensPerPage = DEFAULT_MAX_TOKENS } = options;\n const maxChars = maxTokensPerPage * CHARS_PER_TOKEN;\n\n const aliases = await readPathAliases(projectRoot);\n\n // Trace imports from the page file, up to 2 levels deep\n const tracedFiles = await traceImports(route.filePath, projectRoot, aliases, 2);\n\n const resolvedImports = [...tracedFiles.keys()].filter(p => p !== route.filePath);\n const allSources = [...tracedFiles.values()];\n\n // Build the source context with file headers\n let sourceContext = '';\n for (const [filePath, content] of tracedFiles) {\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length + 1)\n : filePath;\n const section = `\\n// === ${relativePath} ===\\n${content}\\n`;\n\n if (sourceContext.length + section.length > maxChars) {\n // Truncation: include just the page file and skip the rest\n break;\n }\n sourceContext += section;\n }\n\n // Detect auth patterns\n const authConfig = await detectAuth(projectRoot, allSources);\n\n // Check for API dependencies — check both the truncated context and all traced sources\n const combinedSource = allSources.join('\\n');\n const hasApi = hasApiCalls(sourceContext) || hasApiCalls(combinedSource);\n\n // Collect unresolved imports\n const allImportPaths = allSources.flatMap(extractImportPaths);\n const resolvedSet = new Set(resolvedImports.map(p => p));\n const unresolvedImports = allImportPaths\n .filter(p => p.startsWith('.') || p.startsWith('@/') || p.startsWith('~/'))\n .filter(p => {\n // Check if this import was resolved to any file\n const aliasResolved = resolvePathAlias(p, aliases);\n const checkPath = aliasResolved\n ? resolveImportToFile(aliasResolved, projectRoot)\n : resolveImportToFile(p, dirname(route.filePath));\n return !checkPath;\n });\n\n return {\n route,\n sourceContext,\n resolvedImports,\n unresolvedImports: [...new Set(unresolvedImports)],\n authConfig,\n hasApiDependencies: hasApi,\n estimatedTokens: estimateTokens(sourceContext),\n };\n}\n\n/**\n * Analyze all discovered routes in a project.\n */\nexport async function analyzeRoutes(\n routes: RouteInfo[],\n options: AnalyzeOptions,\n): Promise<PageAnalysis[]> {\n const results: PageAnalysis[] = [];\n for (const route of routes) {\n const analysis = await analyzePage(route, options);\n results.push(analysis);\n }\n return results;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { AuthConfig } from './types.js';\n\nconst MIDDLEWARE_FILES = ['middleware.ts', 'middleware.js', 'middleware.tsx', 'middleware.jsx'];\n\n/**\n * Extract cookie names from middleware source code.\n * Looks for patterns like: request.cookies.get('access_token')\n */\nfunction extractCookieNames(source: string): string[] {\n const cookies: string[] = [];\n const regex = /cookies\\.get\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n cookies.push(match[1]);\n }\n return [...new Set(cookies)];\n}\n\n/**\n * Extract API base URL from environment configuration.\n * Looks for NEXT_PUBLIC_API_URL or similar patterns.\n */\nfunction extractApiBaseUrl(source: string): string | null {\n const regex = /process\\.env\\.(\\w*API_URL\\w*)\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/;\n const match = source.match(regex);\n if (match) return match[2];\n\n const simpleRegex = /['\"]https?:\\/\\/[^'\"]+\\/api['\"]/;\n const simpleMatch = source.match(simpleRegex);\n if (simpleMatch) return simpleMatch[0].replace(/['\"]/g, '');\n\n return null;\n}\n\n/**\n * Extract auth check endpoint from source code.\n * Looks for patterns like: fetch(`${base}/auth/me`)\n */\nfunction extractAuthCheckEndpoint(source: string): string | null {\n const patterns = [\n /[`'\"](\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/auth\\/user)[`'\"]/,\n /[`'\"](\\/api\\/user\\/me)[`'\"]/,\n ];\n\n for (const pattern of patterns) {\n const match = source.match(pattern);\n if (match) return match[1];\n }\n\n return null;\n}\n\n/**\n * Detect authentication patterns in the target project.\n *\n * Scans for:\n * 1. middleware.ts/js with cookie checks\n * 2. Auth context providers with auth-check endpoints\n * 3. API base URL configuration\n */\nexport async function detectAuth(projectRoot: string, allSources: string[]): Promise<AuthConfig> {\n const config: AuthConfig = {\n hasAuth: false,\n cookieNames: [],\n authCheckEndpoint: null,\n apiBaseUrl: null,\n };\n\n // 1. Check for middleware\n for (const filename of MIDDLEWARE_FILES) {\n const middlewarePath = join(projectRoot, filename);\n if (existsSync(middlewarePath)) {\n try {\n const source = await readFile(middlewarePath, 'utf-8');\n const cookies = extractCookieNames(source);\n if (cookies.length > 0) {\n config.hasAuth = true;\n config.cookieNames.push(...cookies);\n }\n } catch {\n // Middleware exists but can't be read — skip\n }\n }\n }\n\n // 2. Scan all collected sources for auth patterns\n const combinedSource = allSources.join('\\n');\n\n const authEndpoint = extractAuthCheckEndpoint(combinedSource);\n if (authEndpoint) {\n config.hasAuth = true;\n config.authCheckEndpoint = authEndpoint;\n }\n\n // Look for auth context patterns\n if (/useAuth|AuthProvider|AuthContext|SessionProvider/i.test(combinedSource)) {\n config.hasAuth = true;\n }\n\n // 3. Extract API base URL\n config.apiBaseUrl = extractApiBaseUrl(combinedSource);\n\n return config;\n}\n","/**\n * A single mock response for an API endpoint.\n */\nexport interface MockResponse {\n /** HTTP status code */\n status: number;\n /** Response body as JSON-serializable data */\n body: unknown;\n /** Optional delay in milliseconds before responding */\n delay?: number;\n}\n\n/**\n * A complete mock configuration for rendering a page in a specific state.\n */\nexport interface MockConfig {\n /** State variant name (e.g., \"success\", \"error\", \"empty\", \"loading\") */\n stateName: string;\n /** Map of URL patterns to mock responses */\n apiMocks: Record<string, MockResponse>;\n /** Mock user data for auth, if auth is required */\n authMock: {\n /** Cookies to inject (e.g., { access_token: \"mock_token\" }) */\n cookies: Record<string, string>;\n /** Auth check endpoint mock response */\n authCheckResponse: MockResponse | null;\n } | null;\n /** Sample route parameters for dynamic routes */\n routeParams?: Record<string, string>;\n}\n\n/**\n * State variants to generate for each page.\n */\nexport type StateVariant = 'success' | 'empty' | 'error' | 'loading';\n\nexport const ALL_STATE_VARIANTS: StateVariant[] = ['success', 'empty', 'error', 'loading'];\n\n/**\n * Options for mock generation.\n */\nexport interface MockGeneratorOptions {\n /** Anthropic API key */\n apiKey: string;\n /** Model to use (default: claude-sonnet-4-20250514) */\n model?: string;\n /** State variants to generate (default: all) */\n variants?: StateVariant[];\n}\n","import Anthropic from '@anthropic-ai/sdk';\n\nexport interface LlmResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Simple LLM client wrapper for Anthropic Claude API.\n */\nexport class LlmClient {\n private client: Anthropic;\n private model: string;\n\n constructor(apiKey: string, model: string = 'claude-sonnet-4-20250514') {\n this.client = new Anthropic({ apiKey });\n this.model = model;\n }\n\n async generate(systemPrompt: string, userPrompt: string): Promise<LlmResponse> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n });\n\n const textBlock = response.content.find(block => block.type === 'text');\n const content = textBlock ? textBlock.text : '';\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n }\n}\n","import type { PageAnalysis } from '../analysis/types.js';\n\nexport const SYSTEM_PROMPT = `You are a mock data generator for a UI pre-rendering tool called VibeCanvas.\nYour job is to analyze a Next.js page's source code and generate realistic mock API responses that will make the page render correctly.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces found in the source code.\n3. Generate contextually appropriate data (e.g., real company names for a finance app, realistic usernames for a social app).\n4. For each API endpoint, generate mock responses for these state variants:\n - \"success\": realistic data with multiple items\n - \"empty\": empty collections, zero counts\n - \"error\": API returns HTTP 500 with error message\n - \"loading\": same as success but with a 3000ms delay\n5. Include auth mock data if the page requires authentication.\n6. For dynamic route parameters, generate a realistic sample value.`;\n\n/**\n * Build the user prompt for mock generation from a PageAnalysis.\n */\nexport function buildUserPrompt(analysis: PageAnalysis): string {\n const parts: string[] = [];\n\n parts.push(`## Page Route: ${analysis.route.urlPath}`);\n parts.push(`## Page File: ${analysis.route.filePath}`);\n\n if (analysis.route.isDynamic) {\n parts.push(`## Dynamic Parameters: ${analysis.route.params.map(p => p.name).join(', ')}`);\n }\n\n parts.push('## Source Code Context');\n parts.push(analysis.sourceContext);\n\n if (analysis.authConfig.hasAuth) {\n parts.push('## Auth Configuration');\n parts.push(`- Requires authentication: yes`);\n if (analysis.authConfig.cookieNames.length > 0) {\n parts.push(`- Auth cookies: ${analysis.authConfig.cookieNames.join(', ')}`);\n }\n if (analysis.authConfig.authCheckEndpoint) {\n parts.push(`- Auth check endpoint: ${analysis.authConfig.authCheckEndpoint}`);\n }\n if (analysis.authConfig.apiBaseUrl) {\n parts.push(`- API base URL: ${analysis.authConfig.apiBaseUrl}`);\n }\n }\n\n parts.push(`\n## Required Output Format\n\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" }, // only if dynamic route\n \"apiEndpoints\": [\n {\n \"urlPattern\": \"/api/endpoint\", // the URL path pattern to intercept\n \"method\": \"GET\", // HTTP method\n \"states\": {\n \"success\": { \"status\": 200, \"body\": { ... } },\n \"empty\": { \"status\": 200, \"body\": { ... } },\n \"error\": { \"status\": 500, \"body\": { \"detail\": \"Internal server error\" } },\n \"loading\": { \"status\": 200, \"body\": { ... }, \"delay\": 3000 }\n }\n }\n ],\n \"authMock\": { // only if auth is required\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nGenerate ONLY the JSON. No explanation, no markdown fences.`);\n\n return parts.join('\\n\\n');\n}\n","import type { PageAnalysis } from '../analysis/types.js';\nimport type { MockConfig, MockResponse, StateVariant, MockGeneratorOptions } from './types.js';\nimport { ALL_STATE_VARIANTS } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\ninterface LlmMockOutput {\n routeParams?: Record<string, string>;\n apiEndpoints?: Array<{\n urlPattern: string;\n method: string;\n states: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n // Strip markdown code fences if present\n let cleaned = content.trim();\n if (cleaned.startsWith('```')) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, '').replace(/\\n?```$/, '');\n }\n\n try {\n return JSON.parse(cleaned);\n } catch {\n // Try to find JSON object in the response\n const jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n }\n}\n\n/**\n * Convert LLM output into MockConfig[] (one per state variant).\n */\nfunction convertToMockConfigs(\n output: LlmMockOutput,\n analysis: PageAnalysis,\n variants: StateVariant[],\n): MockConfig[] {\n const configs: MockConfig[] = [];\n\n for (const variant of variants) {\n const apiMocks: Record<string, MockResponse> = {};\n\n if (output.apiEndpoints) {\n for (const endpoint of output.apiEndpoints) {\n const stateData = endpoint.states[variant];\n if (stateData) {\n const key = `${endpoint.method} ${endpoint.urlPattern}`;\n apiMocks[key] = {\n status: stateData.status,\n body: stateData.body,\n delay: stateData.delay,\n };\n }\n }\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n configs.push({\n stateName: variant,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n });\n }\n\n return configs;\n}\n\n/**\n * Generate a fallback MockConfig when LLM fails or page has no API deps.\n */\nfunction generateFallbackConfigs(\n analysis: PageAnalysis,\n variants: StateVariant[],\n): MockConfig[] {\n return variants.map(variant => ({\n stateName: variant,\n apiMocks: {},\n authMock: analysis.authConfig.hasAuth\n ? {\n cookies: Object.fromEntries(\n analysis.authConfig.cookieNames.map(name => [name, 'mock_token_c2d']),\n ),\n authCheckResponse: variant === 'error'\n ? { status: 401, body: { detail: 'Unauthorized' } }\n : { status: 200, body: { id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User' } },\n }\n : null,\n routeParams: analysis.route.isDynamic\n ? Object.fromEntries(analysis.route.params.map(p => [p.name, 'sample-1']))\n : undefined,\n }));\n}\n\n/**\n * Generate mock data for a single page using an LLM.\n *\n * Returns one MockConfig per requested state variant.\n * Falls back to empty mocks if:\n * - The page has no API dependencies\n * - LLM returns invalid data\n * - LLM call fails\n */\nexport async function generateMocks(\n analysis: PageAnalysis,\n options: MockGeneratorOptions,\n): Promise<{ configs: MockConfig[]; tokenUsage: { input: number; output: number } }> {\n const variants = options.variants ?? ALL_STATE_VARIANTS;\n\n // If no API dependencies, just return fallback configs (no LLM call needed)\n if (!analysis.hasApiDependencies) {\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n\n const client = new LlmClient(options.apiKey, options.model);\n const userPrompt = buildUserPrompt(analysis);\n\n try {\n const response = await client.generate(SYSTEM_PROMPT, userPrompt);\n const parsed = parseLlmJson(response.content);\n\n if (!parsed) {\n console.warn(`[c2d] Failed to parse LLM response for ${analysis.route.urlPath}, using fallback`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n }\n\n const configs = convertToMockConfigs(parsed, analysis, variants);\n\n return {\n configs,\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n } catch (error) {\n console.warn(`[c2d] LLM call failed for ${analysis.route.urlPath}: ${error}`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n}\n\n/**\n * Generate mocks for all analyzed pages.\n */\nexport async function generateAllMocks(\n analyses: PageAnalysis[],\n options: MockGeneratorOptions,\n): Promise<{\n results: Map<string, MockConfig[]>;\n totalTokens: { input: number; output: number };\n}> {\n const results = new Map<string, MockConfig[]>();\n const totalTokens = { input: 0, output: 0 };\n\n for (const analysis of analyses) {\n const { configs, tokenUsage } = await generateMocks(analysis, options);\n results.set(analysis.route.urlPath, configs);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n }\n\n return { results, totalTokens };\n}\n","import { chromium, type Browser, type BrowserContext, type Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { MockConfig, MockResponse } from '../mock/types.js';\nimport type { AuthConfig } from '../analysis/types.js';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type {\n RenderResult,\n RenderTask,\n RenderManifest,\n ManifestRoute,\n PreRenderOptions,\n ViewportConfig,\n} from './types.js';\nimport { startDevServer, type DevServerHandle } from './dev-server.js';\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_PAGE_TIMEOUT = 15000;\nconst DEFAULT_SETTLE_TIME = 1500;\nconst DEFAULT_VIEWPORT = { width: 1440, height: 900 };\n\n/**\n * Build the actual URL path for a route, substituting dynamic params.\n */\nfunction buildUrlPath(route: RouteInfo, mockConfig: MockConfig): string {\n let path = route.urlPath;\n if (route.isDynamic && mockConfig.routeParams) {\n for (const param of route.params) {\n const value = mockConfig.routeParams[param.name] || 'sample-1';\n path = path.replace(`:${param.name}`, value);\n // Also handle catch-all notation\n path = path.replace(`:${param.name}+`, value);\n path = path.replace(`:${param.name}*`, value);\n }\n }\n return path;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n * \"/\" → \"index\", \"/dashboard\" → \"dashboard\", \"/editor/:id\" → \"editor-_id\"\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Set up Playwright route interception for a page with the given mock config.\n */\nasync function setupMockInterception(\n page: Page,\n devServerUrl: string,\n mockConfig: MockConfig,\n authConfig: AuthConfig,\n): Promise<void> {\n // 1. Inject auth cookies if needed\n if (mockConfig.authMock) {\n const cookies = Object.entries(mockConfig.authMock.cookies).map(([name, value]) => ({\n name,\n value,\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n } else if (authConfig.hasAuth && authConfig.cookieNames.length > 0) {\n // Fallback: inject dummy cookies for detected auth\n const cookies = authConfig.cookieNames.map(name => ({\n name,\n value: 'c2d_mock_token',\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n }\n\n // 2. Build auth mock response for interception\n const authMockBody = mockConfig.authMock?.authCheckResponse\n ? JSON.stringify(mockConfig.authMock.authCheckResponse.body)\n : JSON.stringify({ id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User', email_verified: true, avatar_url: null, created_at: '2026-01-01T00:00:00Z' });\n\n // Common auth check URL patterns to always intercept\n const AUTH_PATTERNS = ['/auth/me', '/auth/session', '/api/auth/me', '/api/user/me', '/api/auth/session'];\n\n // 3. Intercept API calls\n await page.route('**/*', async (route) => {\n const request = route.request();\n const url = request.url();\n const method = request.method();\n\n // Always intercept auth check endpoints (common patterns + detected endpoint)\n const isAuthCheck = AUTH_PATTERNS.some(p => url.includes(p))\n || (authConfig.authCheckEndpoint && url.includes(authConfig.authCheckEndpoint));\n\n if (isAuthCheck) {\n const status = mockConfig.authMock?.authCheckResponse?.status ?? 200;\n return route.fulfill({\n status,\n contentType: 'application/json',\n body: authMockBody,\n });\n }\n\n // Check API mocks from AI-generated config\n for (const [pattern, mock] of Object.entries(mockConfig.apiMocks)) {\n // Pattern format: \"GET /api/reports\" or \"DELETE /api/reports/{id}\"\n const [mockMethod, ...pathParts] = pattern.split(' ');\n let mockPath = pathParts.join(' ');\n // Convert {param} placeholders to match any value\n mockPath = mockPath.replace(/\\{[^}]+\\}/g, '[^/]+');\n // Also handle * wildcards\n mockPath = mockPath.replace(/\\*/g, '[^/]+');\n\n const pathRegex = new RegExp(mockPath.replace(/\\//g, '\\\\/'));\n if (method === mockMethod && pathRegex.test(url)) {\n if (mock.delay) await new Promise(r => setTimeout(r, mock.delay));\n return route.fulfill({\n status: mock.status,\n contentType: 'application/json',\n body: JSON.stringify(mock.body),\n });\n }\n }\n\n // Pass through all other requests\n return route.continue();\n });\n}\n\n/**\n * Render a single page in a specific state and capture HTML + screenshot.\n */\nasync function renderPage(\n context: BrowserContext,\n devServerUrl: string,\n task: RenderTask,\n outputDir: string,\n options: { pageTimeout: number; settleTime: number },\n viewport?: ViewportConfig,\n): Promise<RenderResult> {\n const { route, mockConfig, authConfig } = task;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Include viewport name in file paths to avoid collisions when rendering multiple viewports\n const filePrefix = viewport ? `${mockConfig.stateName}_${viewport.name}` : mockConfig.stateName;\n const htmlRelPath = join('renders', routeSlug, `${filePrefix}.html`);\n const pngRelPath = join('renders', routeSlug, `${filePrefix}.png`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n const pngAbsPath = join(outputDir, pngRelPath);\n\n const page = await context.newPage();\n\n // Override viewport size for this page if a specific viewport was requested\n if (viewport) {\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n }\n\n try {\n await setupMockInterception(page, devServerUrl, mockConfig, authConfig);\n\n const urlPath = buildUrlPath(route, mockConfig);\n const fullUrl = `${devServerUrl}${urlPath}`;\n\n await page.goto(fullUrl, {\n waitUntil: 'networkidle',\n timeout: options.pageTimeout,\n });\n\n // Extra settle time for React hydration\n await page.waitForTimeout(options.settleTime);\n\n // Inline all external stylesheets so HTML is self-contained\n await page.evaluate(`(() => {\n const links = document.querySelectorAll('link[rel=\"stylesheet\"]');\n links.forEach(link => {\n try {\n const href = link.getAttribute('href');\n if (!href) return;\n for (const sheet of document.styleSheets) {\n if (sheet.href && sheet.href.includes(href.replace(/^\\\\//, ''))) {\n const rules = Array.from(sheet.cssRules).map(r => r.cssText).join('\\\\n');\n const style = document.createElement('style');\n style.textContent = rules;\n link.parentNode.replaceChild(style, link);\n break;\n }\n }\n } catch (e) {}\n });\n document.querySelectorAll('script').forEach(s => s.remove());\n })()`);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n // Capture screenshot\n await page.screenshot({ path: pngAbsPath, fullPage: true });\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\n };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n // Write an error placeholder HTML\n const errorHtml = `<!DOCTYPE html><html><body style=\"display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;color:#666;\">\n <div style=\"text-align:center\"><h2>Render Failed</h2><p>${route.urlPath} [${mockConfig.stateName}]</p><pre style=\"color:#c00\">${errorMsg}</pre></div>\n </body></html>`;\n await writeFile(htmlAbsPath, errorHtml, 'utf-8').catch(() => {});\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: false,\n error: errorMsg,\n viewportName: viewport?.name,\n };\n } finally {\n await page.close();\n }\n}\n\n/**\n * Process render tasks with limited concurrency.\n */\nasync function processWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<RenderResult>,\n onProgress?: (completed: number, total: number, result: RenderResult) => void,\n): Promise<RenderResult[]> {\n const results: RenderResult[] = [];\n const queue = [...items];\n const total = items.length;\n let completed = 0;\n\n async function worker() {\n while (queue.length > 0) {\n const item = queue.shift()!;\n const result = await fn(item);\n results.push(result);\n completed++;\n onProgress?.(completed, total, result);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * Build the render manifest from results.\n */\nfunction buildManifest(\n results: RenderResult[],\n projectName: string,\n viewports?: ViewportConfig[],\n): RenderManifest {\n const routeMap = new Map<string, ManifestRoute>();\n\n // Build a lookup for viewport widths by name\n const viewportWidthMap = new Map<string, number>();\n if (viewports) {\n for (const vp of viewports) {\n viewportWidthMap.set(vp.name, vp.width);\n }\n }\n\n for (const result of results) {\n const key = result.route.urlPath;\n if (!routeMap.has(key)) {\n routeMap.set(key, {\n urlPath: result.route.urlPath,\n filePath: result.route.filePath,\n states: [],\n });\n }\n routeMap.get(key)!.states.push({\n name: result.viewportName\n ? `${result.stateName} (${result.viewportName})`\n : result.stateName,\n htmlPath: result.htmlPath,\n screenshotPath: result.screenshotPath,\n status: result.success ? 'ok' : 'error',\n error: result.error,\n viewport: result.viewportName,\n viewportWidth: result.viewportName\n ? viewportWidthMap.get(result.viewportName)\n : undefined,\n });\n }\n\n return {\n generatedAt: new Date().toISOString(),\n projectName,\n routes: [...routeMap.values()].sort((a, b) => a.urlPath.localeCompare(b.urlPath)),\n };\n}\n\n/**\n * Pre-render all pages with their mock configurations.\n *\n * This is the main entry point for the rendering pipeline:\n * 1. Start dev server (or use provided URL)\n * 2. Launch Playwright browser\n * 3. For each (route, state) pair: intercept APIs, navigate, capture\n * 4. Write manifest.json\n * 5. Clean up\n */\nexport async function preRenderPages(\n tasks: RenderTask[],\n options: PreRenderOptions,\n): Promise<{ results: RenderResult[]; manifest: RenderManifest }> {\n const {\n projectRoot,\n outputDir = join(projectRoot, '.c2d'),\n concurrency = DEFAULT_CONCURRENCY,\n pageTimeout = DEFAULT_PAGE_TIMEOUT,\n settleTime = DEFAULT_SETTLE_TIME,\n viewportWidth = DEFAULT_VIEWPORT.width,\n viewportHeight = DEFAULT_VIEWPORT.height,\n } = options;\n\n // Resolve viewports: if explicit viewports array is provided use it,\n // otherwise fall back to the single viewport from viewportWidth/Height\n // (which themselves default to 1440x900).\n const viewports: ViewportConfig[] | undefined = options.viewports;\n const useMultiViewport = viewports && viewports.length > 0;\n\n // Create output directory\n await mkdir(outputDir, { recursive: true });\n\n // Start dev server\n let devServer: DevServerHandle | null = null;\n try {\n devServer = await startDevServer(projectRoot, {\n port: options.devServerPort,\n devServerUrl: options.devServerUrl,\n });\n\n // Launch browser\n const browser = await chromium.launch({ headless: true });\n const context = await browser.newContext({\n viewport: { width: viewportWidth, height: viewportHeight },\n });\n\n try {\n let results: RenderResult[];\n\n if (useMultiViewport) {\n // Expand tasks: each original task is rendered at each viewport\n const expandedItems: Array<{ task: RenderTask; viewport: ViewportConfig }> = [];\n for (const task of tasks) {\n for (const vp of viewports) {\n expandedItems.push({ task, viewport: vp });\n }\n }\n\n results = await processWithConcurrency(\n expandedItems,\n concurrency,\n ({ task, viewport: vp }) =>\n renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime }, vp),\n options.onProgress,\n );\n } else {\n // Single viewport — backward-compatible path (no viewportName in results)\n results = await processWithConcurrency(\n tasks,\n concurrency,\n (task) => renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime }),\n options.onProgress,\n );\n }\n\n // Read project name from package.json\n let projectName = 'unknown';\n try {\n const pkg = await import(join(projectRoot, 'package.json'), { with: { type: 'json' } });\n projectName = pkg.default?.name || 'unknown';\n } catch {\n // Can't read package.json — use fallback\n }\n\n // Build and write manifest\n const manifest = buildManifest(\n results,\n projectName,\n useMultiViewport ? viewports : undefined,\n );\n await writeFile(\n join(outputDir, 'manifest.json'),\n JSON.stringify(manifest, null, 2),\n 'utf-8',\n );\n\n return { results, manifest };\n } finally {\n await context.close();\n await browser.close();\n }\n } finally {\n if (devServer) {\n await devServer.stop();\n }\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createServer } from 'node:net';\n\n/**\n * Find a free port on the system.\n */\nexport async function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.listen(0, () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not find free port')));\n }\n });\n server.on('error', reject);\n });\n}\n\n/**\n * Wait for a URL to become reachable.\n */\nasync function waitForUrl(url: string, timeoutMs: number = 30000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(2000) });\n // Any response (even redirects) means the server is up\n if (response.status > 0) return;\n } catch {\n // Server not ready yet\n }\n await new Promise(r => setTimeout(r, 500));\n }\n throw new Error(`Dev server did not become ready at ${url} within ${timeoutMs}ms`);\n}\n\n/**\n * Detect the dev command for a project.\n */\nfunction detectDevCommand(projectRoot: string): { cmd: string; args: string[] } {\n if (existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'))) {\n return { cmd: 'npx', args: ['next', 'dev'] };\n }\n // Fallback to npm run dev\n return { cmd: 'npm', args: ['run', 'dev'] };\n}\n\nexport interface DevServerHandle {\n url: string;\n port: number;\n process: ChildProcess | null;\n stop: () => Promise<void>;\n}\n\n/**\n * Start a dev server for the target project.\n *\n * If devServerUrl is provided, uses that instead of starting a new server.\n */\nexport async function startDevServer(\n projectRoot: string,\n options?: { port?: number; devServerUrl?: string },\n): Promise<DevServerHandle> {\n // If a URL is provided, use it directly (user has server running)\n if (options?.devServerUrl) {\n await waitForUrl(options.devServerUrl, 10000);\n return {\n url: options.devServerUrl,\n port: 0,\n process: null,\n stop: async () => {},\n };\n }\n\n const port = options?.port ?? await findFreePort();\n const { cmd, args } = detectDevCommand(projectRoot);\n const fullArgs = [...args, '--port', String(port)];\n\n const child = spawn(cmd, fullArgs, {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, PORT: String(port) },\n });\n\n const url = `http://localhost:${port}`;\n\n // Collect stderr for error reporting\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n // Handle early exit\n const exitPromise = new Promise<never>((_, reject) => {\n child.on('exit', (code) => {\n if (code !== null && code !== 0) {\n reject(new Error(`Dev server exited with code ${code}.\\n${stderr.slice(-500)}`));\n }\n });\n });\n\n // Wait for server to be ready or fail\n try {\n await Promise.race([\n waitForUrl(url, 60000),\n exitPromise,\n ]);\n } catch (err) {\n child.kill('SIGTERM');\n throw err;\n }\n\n return {\n url,\n port,\n process: child,\n stop: async () => {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n resolve();\n }, 5000);\n child.on('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n },\n };\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport sirv from 'sirv';\nimport { handleApiRequest } from './api-routes.js';\n\n/**\n * Options for starting the canvas server.\n */\nexport interface CanvasServerOptions {\n /** Port to listen on (default: 4800) */\n port: number;\n /** Path to the built canvas app directory */\n canvasDir: string;\n /** Path to the .c2d/ output directory */\n c2dDir: string;\n}\n\nconst MAX_PORT_ATTEMPTS = 10;\n\n/**\n * Try to listen on a port. Returns a promise that resolves on success\n * or rejects with the error.\n */\nfunction tryListen(\n requestHandler: (req: IncomingMessage, res: ServerResponse) => void,\n port: number,\n): Promise<{ url: string; port: number; close: () => Promise<void> }> {\n return new Promise((resolve, reject) => {\n const server = createServer(requestHandler);\n server.once('error', reject);\n server.listen(port, () => {\n const actualPort = (server.address() as { port: number }).port;\n resolve({\n url: `http://localhost:${actualPort}`,\n port: actualPort,\n close: () =>\n new Promise<void>((resolveClose, rejectClose) => {\n server.close((err) => {\n if (err) rejectClose(err);\n else resolveClose();\n });\n }),\n });\n });\n });\n}\n\n/**\n * Start the canvas server that serves:\n * 1. API endpoints under /api/\n * 2. Pre-rendered files from .c2d/renders/ under /renders/\n * 3. Canvas app static assets (SPA fallback) for everything else\n *\n * If the default port is in use, tries up to 10 consecutive ports.\n */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir } = options;\n\n // Static file handlers\n const canvasHandler = sirv(canvasDir, { single: true, dev: true });\n const rendersDir = join(c2dDir, 'renders');\n const rendersHandler = sirv(rendersDir, { dev: true });\n\n // Request handler\n const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n // CORS headers on all responses\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n // API routes\n if (url.startsWith('/api/')) {\n try {\n const handled = await handleApiRequest(req, res, c2dDir);\n if (!handled) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal server error';\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: message }));\n }\n return;\n }\n\n // Renders (pre-rendered HTML/screenshots)\n if (url.startsWith('/renders/')) {\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\n });\n return;\n }\n\n // Canvas app (SPA with fallback to index.html)\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n };\n\n // Try ports starting from the configured port\n for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {\n const tryPort = port + attempt;\n try {\n return await tryListen(requestHandler, tryPort);\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < MAX_PORT_ATTEMPTS - 1) {\n continue;\n }\n throw err;\n }\n }\n\n throw new Error(`Could not find an available port (tried ${port}-${port + MAX_PORT_ATTEMPTS - 1})`);\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/**\n * A single pen stroke on the drawing canvas.\n */\nexport interface DrawingStroke {\n points: { x: number; y: number }[];\n color: string;\n width: number;\n}\n\n/**\n * A comment pinned to a canvas coordinate.\n */\nexport interface Comment {\n id: string;\n x: number;\n y: number;\n text: string;\n author: string;\n timestamp: string;\n}\n\n/**\n * Handle API requests under the /api/ prefix.\n *\n * Returns true if the request was handled, false otherwise.\n */\nexport async function handleApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<boolean> {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n if (url === '/api/manifest' && method === 'GET') {\n await handleGetManifest(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'GET') {\n await handleGetComments(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'POST') {\n await handlePostComment(req, res, c2dDir);\n return true;\n }\n\n const deleteMatch = url.match(/^\\/api\\/comments\\/(.+)$/);\n if (deleteMatch && method === 'DELETE') {\n await handleDeleteComment(res, c2dDir, deleteMatch[1]);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'GET') {\n await handleGetDrawings(res, c2dDir);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'POST') {\n await handlePostDrawings(req, res, c2dDir);\n return true;\n }\n\n return false;\n}\n\n// --- Handlers ---\n\nasync function handleGetManifest(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const manifestPath = join(c2dDir, 'manifest.json');\n if (!existsSync(manifestPath)) {\n sendJson(res, 404, { error: 'manifest.json not found' });\n return;\n }\n const data = await readFile(manifestPath, 'utf-8');\n sendRawJson(res, 200, data);\n}\n\nasync function handleGetComments(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n sendJson(res, 200, comments);\n}\n\nasync function handlePostComment(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!isValidCommentInput(parsed)) {\n sendJson(res, 400, { error: 'Missing required fields: x, y, text, author' });\n return;\n }\n\n const comment: Comment = {\n id: randomUUID(),\n x: parsed.x,\n y: parsed.y,\n text: parsed.text,\n author: parsed.author,\n timestamp: new Date().toISOString(),\n };\n\n const comments = await loadComments(c2dDir);\n comments.push(comment);\n await saveComments(c2dDir, comments);\n sendJson(res, 201, comment);\n}\n\nasync function handleDeleteComment(\n res: ServerResponse,\n c2dDir: string,\n id: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n const index = comments.findIndex(c => c.id === id);\n if (index === -1) {\n sendJson(res, 404, { error: 'Comment not found' });\n return;\n }\n comments.splice(index, 1);\n await saveComments(c2dDir, comments);\n sendJson(res, 200, { ok: true });\n}\n\n// --- Drawing Handlers ---\n\nasync function handleGetDrawings(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const drawings = await loadDrawings(c2dDir);\n sendJson(res, 200, drawings);\n}\n\nasync function handlePostDrawings(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!Array.isArray(parsed)) {\n sendJson(res, 400, { error: 'Body must be an array of strokes' });\n return;\n }\n\n await saveDrawings(c2dDir, parsed as DrawingStroke[]);\n sendJson(res, 200, { ok: true });\n}\n\nasync function loadDrawings(c2dDir: string): Promise<DrawingStroke[]> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n if (!existsSync(drawingsPath)) {\n return [];\n }\n const data = await readFile(drawingsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveDrawings(c2dDir: string, drawings: DrawingStroke[]): Promise<void> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n const dir = dirname(drawingsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(drawingsPath, JSON.stringify(drawings, null, 2), 'utf-8');\n}\n\n// --- Helpers ---\n\nfunction isValidCommentInput(\n value: unknown,\n): value is { x: number; y: number; text: string; author: string } {\n if (typeof value !== 'object' || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.x === 'number' &&\n typeof obj.y === 'number' &&\n typeof obj.text === 'string' &&\n typeof obj.author === 'string'\n );\n}\n\nasync function loadComments(c2dDir: string): Promise<Comment[]> {\n const commentsPath = join(c2dDir, 'comments.json');\n if (!existsSync(commentsPath)) {\n return [];\n }\n const data = await readFile(commentsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveComments(c2dDir: string, comments: Comment[]): Promise<void> {\n const commentsPath = join(c2dDir, 'comments.json');\n const dir = dirname(commentsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(commentsPath, JSON.stringify(comments, null, 2), 'utf-8');\n}\n\nfunction readRequestBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n req.on('error', reject);\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(body);\n}\n\nfunction sendRawJson(res: ServerResponse, status: number, jsonString: string): void {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(jsonString);\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface VibeCanvasConfig {\n apiKey: string;\n port: number;\n excludeRoutes: string[];\n devServerUrl?: string;\n devServerCommand?: string;\n}\n\nconst DEFAULT_PORT = 4800;\n\n/**\n * Load configuration from environment variables and optional config file.\n */\nexport async function loadConfig(projectRoot: string): Promise<VibeCanvasConfig> {\n let fileConfig: Partial<VibeCanvasConfig> = {};\n\n // Try to load c2d.config.js\n const configPath = join(projectRoot, 'c2d.config.js');\n if (existsSync(configPath)) {\n try {\n const mod = await import(configPath);\n fileConfig = mod.default || mod;\n } catch {\n // Config file exists but can't be loaded — use defaults\n }\n }\n\n const apiKey = process.env.C2D_API_KEY || fileConfig.apiKey || '';\n\n return {\n apiKey,\n port: fileConfig.port || Number(process.env.C2D_PORT) || DEFAULT_PORT,\n excludeRoutes: fileConfig.excludeRoutes || [],\n devServerUrl: fileConfig.devServerUrl || process.env.C2D_DEV_SERVER_URL,\n devServerCommand: fileConfig.devServerCommand,\n };\n}\n\n/**\n * Detect if the current directory is a Next.js App Router project.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\n const hasNextConfig =\n existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'));\n\n // Check both app/ and src/app/ (common Next.js structures)\n let appDir = join(projectRoot, 'app');\n let hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'app');\n hasAppDir = existsSync(appDir);\n }\n\n let projectName = 'unknown';\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n projectName = pkg.name || 'unknown';\n } catch {\n // No package.json\n }\n\n return {\n isNextJs: hasNextConfig,\n appDir: hasAppDir ? appDir : null,\n projectName,\n };\n}\n","/**\n * Simple console progress utilities for the CLI.\n */\n\nconst COLORS = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n};\n\nexport function log(message: string): void {\n console.log(`${COLORS.dim}[c2d]${COLORS.reset} ${message}`);\n}\n\nexport function success(message: string): void {\n console.log(`${COLORS.green} ✓${COLORS.reset} ${message}`);\n}\n\nexport function warn(message: string): void {\n console.log(`${COLORS.yellow} ⚠${COLORS.reset} ${message}`);\n}\n\nexport function error(message: string): void {\n console.error(`${COLORS.red} ✗${COLORS.reset} ${message}`);\n}\n\nexport function header(message: string): void {\n console.log(`\\n${COLORS.bold}${COLORS.cyan}${message}${COLORS.reset}`);\n}\n\nexport function step(current: number, total: number, message: string): void {\n console.log(`${COLORS.dim} [${current}/${total}]${COLORS.reset} ${message}`);\n}\n\nexport function banner(): void {\n console.log(`\n${COLORS.bold}${COLORS.cyan} Code to Design${COLORS.reset} ${COLORS.dim}v0.1.0${COLORS.reset}\n${COLORS.dim} AI-powered UI review canvas${COLORS.reset}\n`);\n}\n"],"mappings":"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","names":["join","mkdir","existsSync","readFile","join","existsSync","join","join","existsSync","readFile","error","join","existsSync","join","resolve","join","createServer","join","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","resolve","createServer","join","existsSync","readFile","join","join","existsSync","mkdir","r","resolve","dirname","writeFile"]}