aerocoding 0.1.28 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1115,8 +1115,12 @@ var projectConfigSchema = z.object({
1115
1115
  $schema: z.string().optional().default("https://aerocoding.dev/schema.json"),
1116
1116
  /** Project UUID from aerocoding.dev */
1117
1117
  projectId: z.string().uuid(),
1118
- /** Template ID for architecture generation */
1118
+ /** Template ID for architecture generation (legacy, prefer backendTemplateId/frontendTemplateId) */
1119
1119
  templateId: z.string().min(1),
1120
+ /** Backend template ID */
1121
+ backendTemplateId: z.string().min(1).optional(),
1122
+ /** Frontend template ID */
1123
+ frontendTemplateId: z.string().min(1).optional(),
1120
1124
  /** Template version at project creation */
1121
1125
  templateVersion: z.string().optional(),
1122
1126
  /** Root namespace/package name */
@@ -1149,6 +1153,8 @@ function createProjectConfig(options) {
1149
1153
  $schema: "https://aerocoding.dev/schema.json",
1150
1154
  projectId: options.projectId,
1151
1155
  templateId: options.templateId,
1156
+ backendTemplateId: options.backendTemplateId,
1157
+ frontendTemplateId: options.frontendTemplateId,
1152
1158
  templateVersion: options.templateVersion,
1153
1159
  namespace: options.namespace,
1154
1160
  organizationId: options.organizationId,
@@ -1316,32 +1322,65 @@ async function createCommand(projectName, options) {
1316
1322
  }
1317
1323
  } catch {
1318
1324
  }
1319
- let templateId = options.template;
1320
- if (!templateId) {
1325
+ let backendTemplateId = options.template;
1326
+ const hasBackend = !!project.backendFramework;
1327
+ if (hasBackend && !backendTemplateId) {
1321
1328
  const templateSpinner = p.spinner();
1322
- templateSpinner.start("Loading templates...");
1329
+ templateSpinner.start("Loading backend templates...");
1323
1330
  const templateResult = await apiClient.getTemplates({
1324
1331
  category: "backend",
1325
1332
  language: project.backendFramework || void 0
1326
1333
  });
1327
- templateSpinner.stop("Templates loaded");
1334
+ templateSpinner.stop("Backend templates loaded");
1328
1335
  if (templateResult.templates.length === 0) {
1329
- p.cancel("No templates available for this project's framework.");
1330
- process.exit(1);
1336
+ p.log.warn("No backend templates available for this project's framework.");
1337
+ } else {
1338
+ const selectedTemplate = await p.select({
1339
+ message: "Select backend architecture template",
1340
+ options: templateResult.templates.map((tmpl) => ({
1341
+ value: tmpl.id,
1342
+ label: tmpl.name,
1343
+ hint: tmpl.description || `${tmpl.tier} tier`
1344
+ }))
1345
+ });
1346
+ if (p.isCancel(selectedTemplate)) {
1347
+ p.cancel("Operation cancelled.");
1348
+ process.exit(0);
1349
+ }
1350
+ backendTemplateId = selectedTemplate;
1331
1351
  }
1332
- const selectedTemplate = await p.select({
1333
- message: "Select architecture template",
1334
- options: templateResult.templates.map((tmpl) => ({
1335
- value: tmpl.id,
1336
- label: tmpl.name,
1337
- hint: tmpl.description || `${tmpl.tier} tier`
1338
- }))
1352
+ }
1353
+ let frontendTemplateId;
1354
+ const hasFrontend = !!project.frontendFramework;
1355
+ if (hasFrontend) {
1356
+ const frontendSpinner = p.spinner();
1357
+ frontendSpinner.start("Loading frontend templates...");
1358
+ const frontendResult = await apiClient.getTemplates({
1359
+ category: "frontend",
1360
+ framework: project.frontendFramework || void 0
1339
1361
  });
1340
- if (p.isCancel(selectedTemplate)) {
1341
- p.cancel("Operation cancelled.");
1342
- process.exit(0);
1362
+ frontendSpinner.stop("Frontend templates loaded");
1363
+ if (frontendResult.templates.length === 0) {
1364
+ p.log.warn("No frontend templates available for this project's framework.");
1365
+ } else {
1366
+ const selectedFrontend = await p.select({
1367
+ message: "Select frontend architecture template",
1368
+ options: frontendResult.templates.map((tmpl) => ({
1369
+ value: tmpl.id,
1370
+ label: tmpl.name,
1371
+ hint: tmpl.description || `${tmpl.tier} tier`
1372
+ }))
1373
+ });
1374
+ if (p.isCancel(selectedFrontend)) {
1375
+ p.cancel("Operation cancelled.");
1376
+ process.exit(0);
1377
+ }
1378
+ frontendTemplateId = selectedFrontend;
1343
1379
  }
1344
- templateId = selectedTemplate;
1380
+ }
1381
+ if (!backendTemplateId && !frontendTemplateId) {
1382
+ p.cancel("No templates selected. At least one backend or frontend template is required.");
1383
+ process.exit(1);
1345
1384
  }
1346
1385
  const diagrams = project.schema?.diagrams || [];
1347
1386
  const hasMultipleDiagrams = diagrams.length > 1;
@@ -1401,50 +1440,72 @@ async function createCommand(projectName, options) {
1401
1440
  const useContexts = archStyleChoice === "bounded-contexts";
1402
1441
  const estimateSpinner = p.spinner();
1403
1442
  estimateSpinner.start("Calculating credit cost...");
1404
- let estimatedCredits = 0;
1405
1443
  let creditsRemaining = 0;
1406
- let estimatedFiles = [];
1407
- let estimatedEntities = 0;
1444
+ let backendEstimatedCredits = 0;
1445
+ let backendEstimatedFiles = [];
1446
+ let backendEstimatedEntities = 0;
1447
+ let frontendEstimatedCredits = 0;
1448
+ let frontendEstimatedFiles = [];
1449
+ let frontendEstimatedEntities = 0;
1408
1450
  const estimateDiagramIds = selectedDiagramIds.length < diagrams.length ? selectedDiagramIds : void 0;
1451
+ const featureFlags = {
1452
+ includeDtos: true,
1453
+ includeUseCases: true,
1454
+ includeMappers: true,
1455
+ includeControllers: true,
1456
+ includeEfConfig: true,
1457
+ includeValidation: true,
1458
+ includeDtoValidation: true,
1459
+ includeUnitTests: true,
1460
+ includeIntegrationTests: true,
1461
+ includeStarterFiles: true,
1462
+ includeReactions: true,
1463
+ includeOutbox: true,
1464
+ includeInbox: true
1465
+ };
1409
1466
  try {
1410
- const estimate = await apiClient.estimateCreditCost({
1411
- projectId,
1412
- templateId,
1413
- options: {
1414
- featureFlags: {
1415
- includeDtos: true,
1416
- includeUseCases: true,
1417
- includeMappers: true,
1418
- includeControllers: true,
1419
- includeEfConfig: true,
1420
- includeValidation: true,
1421
- includeDtoValidation: true,
1422
- includeUnitTests: true,
1423
- includeIntegrationTests: true,
1424
- includeStarterFiles: true,
1425
- includeReactions: true,
1426
- includeOutbox: true,
1427
- includeInbox: true
1428
- },
1429
- useContexts,
1430
- diagramIds: estimateDiagramIds
1431
- }
1432
- });
1433
- estimatedCredits = estimate.estimatedCredits;
1434
- estimatedFiles = estimate.files || [];
1435
- estimatedEntities = estimate.entities || 0;
1467
+ if (backendTemplateId) {
1468
+ const backendEstimate = await apiClient.estimateCreditCost({
1469
+ projectId,
1470
+ templateId: backendTemplateId,
1471
+ options: {
1472
+ featureFlags,
1473
+ useContexts,
1474
+ diagramIds: estimateDiagramIds
1475
+ }
1476
+ });
1477
+ backendEstimatedCredits = backendEstimate.estimatedCredits;
1478
+ backendEstimatedFiles = backendEstimate.files || [];
1479
+ backendEstimatedEntities = backendEstimate.entities || 0;
1480
+ }
1481
+ if (frontendTemplateId) {
1482
+ const frontendEstimate = await apiClient.estimateCreditCost({
1483
+ projectId,
1484
+ templateId: frontendTemplateId,
1485
+ options: {
1486
+ featureFlags,
1487
+ useContexts,
1488
+ diagramIds: estimateDiagramIds
1489
+ }
1490
+ });
1491
+ frontendEstimatedCredits = frontendEstimate.estimatedCredits;
1492
+ frontendEstimatedFiles = frontendEstimate.files || [];
1493
+ frontendEstimatedEntities = frontendEstimate.entities || 0;
1494
+ }
1436
1495
  const creditUsage = await apiClient.getCreditUsage(organizationId);
1437
1496
  creditsRemaining = creditUsage.remaining;
1438
1497
  estimateSpinner.stop("Credit estimate calculated");
1439
1498
  } catch {
1440
1499
  estimateSpinner.stop("Could not estimate credits (will be calculated on generation)");
1441
1500
  }
1442
- const hasEnoughCredits = estimatedCredits === 0 || creditsRemaining >= estimatedCredits;
1501
+ const totalEstimatedCredits = backendEstimatedCredits + frontendEstimatedCredits;
1502
+ const totalEstimatedFiles = backendEstimatedFiles.length + frontendEstimatedFiles.length;
1503
+ const totalEstimatedEntities = backendEstimatedEntities + frontendEstimatedEntities;
1504
+ const hasEnoughCredits = totalEstimatedCredits === 0 || creditsRemaining >= totalEstimatedCredits;
1443
1505
  console.log("");
1444
1506
  console.log(chalk7.bold(" Generation Summary"));
1445
1507
  console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1446
1508
  console.log(chalk7.gray(" Project:"), chalk7.white(project.name));
1447
- console.log(chalk7.gray(" Template:"), chalk7.cyan(templateId));
1448
1509
  console.log(chalk7.gray(" Namespace:"), chalk7.cyan(namespace));
1449
1510
  console.log(chalk7.gray(" Directory:"), chalk7.cyan(`${safeName}/`));
1450
1511
  console.log(
@@ -1461,14 +1522,45 @@ async function createCommand(projectName, options) {
1461
1522
  console.log(chalk7.gray(" Bounded Contexts:"), chalk7.cyan(`${selectedCount}/${totalCount} (${selectedNames})`));
1462
1523
  }
1463
1524
  }
1464
- if (estimatedFiles.length > 0) {
1525
+ console.log("");
1526
+ console.log(chalk7.bold(" Templates"));
1527
+ console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1528
+ if (backendTemplateId) {
1529
+ console.log(chalk7.gray(" Backend:"), chalk7.cyan(backendTemplateId));
1530
+ }
1531
+ if (frontendTemplateId) {
1532
+ console.log(chalk7.gray(" Frontend:"), chalk7.cyan(frontendTemplateId));
1533
+ }
1534
+ if (backendEstimatedFiles.length > 0) {
1535
+ console.log("");
1536
+ console.log(chalk7.bold(` Backend Files (${backendTemplateId})`));
1537
+ console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1538
+ const backendCategories = categorizeFilePaths(backendEstimatedFiles);
1539
+ const backendMaxNameLength = Math.max(...backendCategories.map((c) => c.name.length), 8);
1540
+ for (const category of backendCategories) {
1541
+ const padding = " ".repeat(backendMaxNameLength - category.name.length + 2);
1542
+ const countStr = category.count.toString().padStart(3, " ");
1543
+ console.log(
1544
+ chalk7.gray(` ${category.name}${padding}`),
1545
+ chalk7.cyan(`${countStr} files`)
1546
+ );
1547
+ }
1548
+ console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1549
+ const subtotalPadding = " ".repeat(backendMaxNameLength - 8 + 2);
1550
+ const subtotalStr = backendEstimatedFiles.length.toString().padStart(3, " ");
1551
+ console.log(
1552
+ chalk7.white(` Subtotal${subtotalPadding}`),
1553
+ chalk7.bold.cyan(`${subtotalStr} files`)
1554
+ );
1555
+ }
1556
+ if (frontendEstimatedFiles.length > 0) {
1465
1557
  console.log("");
1466
- console.log(chalk7.bold(" Files to Generate"));
1558
+ console.log(chalk7.bold(` Frontend Files (${frontendTemplateId})`));
1467
1559
  console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1468
- const categories = categorizeFilePaths(estimatedFiles);
1469
- const maxNameLength = Math.max(...categories.map((c) => c.name.length));
1470
- for (const category of categories) {
1471
- const padding = " ".repeat(maxNameLength - category.name.length + 2);
1560
+ const frontendCategories = categorizeFilePaths(frontendEstimatedFiles);
1561
+ const frontendMaxNameLength = Math.max(...frontendCategories.map((c) => c.name.length), 8);
1562
+ for (const category of frontendCategories) {
1563
+ const padding = " ".repeat(frontendMaxNameLength - category.name.length + 2);
1472
1564
  const countStr = category.count.toString().padStart(3, " ");
1473
1565
  console.log(
1474
1566
  chalk7.gray(` ${category.name}${padding}`),
@@ -1476,21 +1568,43 @@ async function createCommand(projectName, options) {
1476
1568
  );
1477
1569
  }
1478
1570
  console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1479
- const totalPadding = " ".repeat(maxNameLength - 5 + 2);
1480
- const totalStr = estimatedFiles.length.toString().padStart(3, " ");
1571
+ const subtotalPadding = " ".repeat(frontendMaxNameLength - 8 + 2);
1572
+ const subtotalStr = frontendEstimatedFiles.length.toString().padStart(3, " ");
1573
+ console.log(
1574
+ chalk7.white(` Subtotal${subtotalPadding}`),
1575
+ chalk7.bold.cyan(`${subtotalStr} files`)
1576
+ );
1577
+ }
1578
+ if (backendEstimatedFiles.length > 0 && frontendEstimatedFiles.length > 0) {
1579
+ console.log("");
1580
+ console.log(chalk7.gray(" \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
1481
1581
  console.log(
1482
- chalk7.white(` Total${totalPadding}`),
1483
- chalk7.bold.cyan(`${totalStr} files`)
1582
+ chalk7.bold.white(" TOTAL "),
1583
+ chalk7.bold.green(`${totalEstimatedFiles.toString().padStart(3, " ")} files`)
1484
1584
  );
1485
- console.log(chalk7.gray(" Entities:"), chalk7.cyan(estimatedEntities));
1585
+ console.log(chalk7.gray(" Entities:"), chalk7.cyan(totalEstimatedEntities));
1586
+ } else if (totalEstimatedFiles > 0) {
1587
+ console.log(chalk7.gray(" Entities:"), chalk7.cyan(totalEstimatedEntities));
1486
1588
  }
1487
1589
  console.log("");
1488
1590
  console.log(chalk7.bold(" Credits"));
1489
1591
  console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1490
- if (estimatedCredits > 0) {
1592
+ if (backendEstimatedCredits > 0) {
1593
+ console.log(
1594
+ chalk7.gray(" Backend:"),
1595
+ chalk7.yellow(`${backendEstimatedCredits} credits`)
1596
+ );
1597
+ }
1598
+ if (frontendEstimatedCredits > 0) {
1491
1599
  console.log(
1492
- chalk7.white(" Cost:"),
1493
- hasEnoughCredits ? chalk7.bold.yellow(`${estimatedCredits} credits`) : chalk7.bold.red(`${estimatedCredits} credits`)
1600
+ chalk7.gray(" Frontend:"),
1601
+ chalk7.yellow(`${frontendEstimatedCredits} credits`)
1602
+ );
1603
+ }
1604
+ if (totalEstimatedCredits > 0) {
1605
+ console.log(
1606
+ chalk7.white(" Total Cost:"),
1607
+ hasEnoughCredits ? chalk7.bold.yellow(`${totalEstimatedCredits} credits`) : chalk7.bold.red(`${totalEstimatedCredits} credits`)
1494
1608
  );
1495
1609
  }
1496
1610
  console.log(
@@ -1500,12 +1614,12 @@ async function createCommand(projectName, options) {
1500
1614
  console.log("");
1501
1615
  if (!hasEnoughCredits) {
1502
1616
  console.log(chalk7.red(" \u26A0 Not enough credits for this generation."));
1503
- console.log(chalk7.gray(` Need ${estimatedCredits - creditsRemaining} more credits.
1617
+ console.log(chalk7.gray(` Need ${totalEstimatedCredits - creditsRemaining} more credits.
1504
1618
  `));
1505
1619
  process.exit(1);
1506
1620
  }
1507
1621
  const proceed = await p.confirm({
1508
- message: estimatedCredits > 0 ? `Proceed with generation? (~${estimatedCredits} credits)` : "Proceed with generation?",
1622
+ message: totalEstimatedCredits > 0 ? `Proceed with generation? (~${totalEstimatedCredits} credits)` : "Proceed with generation?",
1509
1623
  initialValue: true
1510
1624
  });
1511
1625
  if (p.isCancel(proceed) || !proceed) {
@@ -1516,47 +1630,68 @@ async function createCommand(projectName, options) {
1516
1630
  dirSpinner.start(`Creating ${safeName}/...`);
1517
1631
  await mkdir(projectDir, { recursive: true });
1518
1632
  dirSpinner.stop(`Created ${safeName}/`);
1519
- const genSpinner = ora2({ text: "Generating architecture...", color: "cyan" }).start();
1520
- const result = await apiClient.generateCode({
1521
- projectId,
1522
- templateId,
1523
- options: {
1524
- includeValidations: true,
1525
- includeComments: true,
1526
- featureFlags: {
1527
- includeDtos: true,
1528
- includeUseCases: true,
1529
- includeMappers: true,
1530
- includeControllers: true,
1531
- includeEfConfig: true,
1532
- includeValidation: true,
1533
- includeDtoValidation: true,
1534
- includeUnitTests: true,
1535
- includeIntegrationTests: true,
1536
- includeStarterFiles: true,
1537
- includeReactions: true,
1538
- includeOutbox: true,
1539
- includeInbox: true
1540
- },
1541
- useContexts,
1542
- diagramIds: estimateDiagramIds
1543
- // Filter by selected bounded contexts
1633
+ const allGeneratedFiles = [];
1634
+ let totalCreditsUsed = 0;
1635
+ let totalCreditsRemaining = creditsRemaining;
1636
+ if (backendTemplateId) {
1637
+ const backendSpinner = ora2({ text: "Generating backend architecture...", color: "cyan" }).start();
1638
+ const backendResult = await apiClient.generateCode({
1639
+ projectId,
1640
+ templateId: backendTemplateId,
1641
+ options: {
1642
+ includeValidations: true,
1643
+ includeComments: true,
1644
+ featureFlags,
1645
+ useContexts,
1646
+ diagramIds: estimateDiagramIds
1647
+ }
1648
+ });
1649
+ const backendFiles = (backendResult.files || []).map((file) => ({
1650
+ ...file,
1651
+ path: `backend/${file.path}`
1652
+ }));
1653
+ allGeneratedFiles.push(...backendFiles);
1654
+ if (backendResult.creditsUsed !== void 0) {
1655
+ totalCreditsUsed += backendResult.creditsUsed;
1656
+ totalCreditsRemaining = backendResult.creditsRemaining ?? totalCreditsRemaining;
1544
1657
  }
1545
- });
1546
- genSpinner.succeed(chalk7.green(`Generated ${result.files?.length || 0} files`));
1658
+ backendSpinner.succeed(chalk7.green(`Backend: ${backendFiles.length} files generated`));
1659
+ }
1660
+ if (frontendTemplateId) {
1661
+ const frontendSpinner = ora2({ text: "Generating frontend architecture...", color: "cyan" }).start();
1662
+ const frontendResult = await apiClient.generateCode({
1663
+ projectId,
1664
+ templateId: frontendTemplateId,
1665
+ options: {
1666
+ includeValidations: true,
1667
+ includeComments: true,
1668
+ featureFlags,
1669
+ useContexts,
1670
+ diagramIds: estimateDiagramIds
1671
+ }
1672
+ });
1673
+ const frontendFiles = (frontendResult.files || []).map((file) => ({
1674
+ ...file,
1675
+ path: `frontend/${file.path}`
1676
+ }));
1677
+ allGeneratedFiles.push(...frontendFiles);
1678
+ if (frontendResult.creditsUsed !== void 0) {
1679
+ totalCreditsUsed += frontendResult.creditsUsed;
1680
+ totalCreditsRemaining = frontendResult.creditsRemaining ?? totalCreditsRemaining;
1681
+ }
1682
+ frontendSpinner.succeed(chalk7.green(`Frontend: ${frontendFiles.length} files generated`));
1683
+ }
1547
1684
  const writeSpinner = p.spinner();
1548
1685
  writeSpinner.start("Writing files...");
1549
- const organizedFiles = result.files.map((file) => ({
1550
- ...file,
1551
- path: `backend/${file.path}`
1552
- }));
1553
- await writeGeneratedFiles(organizedFiles, projectDir, false);
1554
- writeSpinner.stop(`Wrote ${organizedFiles.length} files`);
1686
+ await writeGeneratedFiles(allGeneratedFiles, projectDir, false);
1687
+ writeSpinner.stop(`Wrote ${allGeneratedFiles.length} files`);
1555
1688
  const configSpinner = p.spinner();
1556
1689
  configSpinner.start("Creating config files...");
1557
1690
  const projectConfig = createProjectConfig({
1558
1691
  projectId,
1559
- templateId,
1692
+ templateId: backendTemplateId || frontendTemplateId || "",
1693
+ backendTemplateId,
1694
+ frontendTemplateId,
1560
1695
  templateVersion: "1.0.0",
1561
1696
  // TODO: get from template
1562
1697
  namespace,
@@ -1565,7 +1700,7 @@ async function createCommand(projectName, options) {
1565
1700
  });
1566
1701
  await saveProjectConfig(projectConfig, projectDir);
1567
1702
  let manifest = createEmptyManifest("1.0.0");
1568
- for (const file of organizedFiles) {
1703
+ for (const file of allGeneratedFiles) {
1569
1704
  const hash = hashString(file.content);
1570
1705
  manifest = setManifestFile(manifest, file.path, {
1571
1706
  hash,
@@ -1590,13 +1725,21 @@ async function createCommand(projectName, options) {
1590
1725
  console.log(chalk7.bold(" Project Created Successfully!"));
1591
1726
  console.log(chalk7.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1592
1727
  console.log(chalk7.gray(" Directory:"), chalk7.cyan(safeName + "/"));
1593
- console.log(chalk7.gray(" Files:"), chalk7.cyan(organizedFiles.length));
1728
+ const backendFileCount = allGeneratedFiles.filter((f) => f.path.startsWith("backend/")).length;
1729
+ const frontendFileCount = allGeneratedFiles.filter((f) => f.path.startsWith("frontend/")).length;
1730
+ if (backendFileCount > 0 && frontendFileCount > 0) {
1731
+ console.log(chalk7.gray(" Backend:"), chalk7.cyan(`${backendFileCount} files`));
1732
+ console.log(chalk7.gray(" Frontend:"), chalk7.cyan(`${frontendFileCount} files`));
1733
+ console.log(chalk7.gray(" Total:"), chalk7.bold.cyan(`${allGeneratedFiles.length} files`));
1734
+ } else {
1735
+ console.log(chalk7.gray(" Files:"), chalk7.cyan(allGeneratedFiles.length));
1736
+ }
1594
1737
  console.log(chalk7.gray(" Config:"), chalk7.cyan(PROJECT_CONFIG_FILENAME));
1595
1738
  console.log(chalk7.gray(" Manifest:"), chalk7.cyan(MANIFEST_FILENAME));
1596
- if (result.creditsUsed !== void 0) {
1739
+ if (totalCreditsUsed > 0) {
1597
1740
  console.log("");
1598
- console.log(chalk7.gray(" Credits used:"), chalk7.yellow(result.creditsUsed));
1599
- console.log(chalk7.gray(" Credits remaining:"), chalk7.green(result.creditsRemaining));
1741
+ console.log(chalk7.gray(" Credits used:"), chalk7.yellow(totalCreditsUsed));
1742
+ console.log(chalk7.gray(" Credits remaining:"), chalk7.green(totalCreditsRemaining));
1600
1743
  }
1601
1744
  p.outro(
1602
1745
  chalk7.green("Project ready!") + "\n\n" + chalk7.gray(" Next steps:\n") + chalk7.cyan(` cd ${safeName}