aerocoding 0.1.27 → 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 +273 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
1320
|
-
|
|
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("
|
|
1334
|
+
templateSpinner.stop("Backend templates loaded");
|
|
1328
1335
|
if (templateResult.templates.length === 0) {
|
|
1329
|
-
p.
|
|
1330
|
-
|
|
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
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
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
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -1378,55 +1417,101 @@ async function createCommand(projectName, options) {
|
|
|
1378
1417
|
p.cancel("Operation cancelled.");
|
|
1379
1418
|
process.exit(0);
|
|
1380
1419
|
}
|
|
1420
|
+
const archStyleChoice = await p.select({
|
|
1421
|
+
message: "Architecture style",
|
|
1422
|
+
options: [
|
|
1423
|
+
{
|
|
1424
|
+
value: "bounded-contexts",
|
|
1425
|
+
label: "Bounded Contexts",
|
|
1426
|
+
hint: "DDD-style: separate folders per module (recommended)"
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
value: "flat",
|
|
1430
|
+
label: "Flat Structure",
|
|
1431
|
+
hint: "All layers in single structure (simpler)"
|
|
1432
|
+
}
|
|
1433
|
+
],
|
|
1434
|
+
initialValue: "bounded-contexts"
|
|
1435
|
+
});
|
|
1436
|
+
if (p.isCancel(archStyleChoice)) {
|
|
1437
|
+
p.cancel("Operation cancelled.");
|
|
1438
|
+
process.exit(0);
|
|
1439
|
+
}
|
|
1440
|
+
const useContexts = archStyleChoice === "bounded-contexts";
|
|
1381
1441
|
const estimateSpinner = p.spinner();
|
|
1382
1442
|
estimateSpinner.start("Calculating credit cost...");
|
|
1383
|
-
let estimatedCredits = 0;
|
|
1384
1443
|
let creditsRemaining = 0;
|
|
1385
|
-
let
|
|
1386
|
-
let
|
|
1444
|
+
let backendEstimatedCredits = 0;
|
|
1445
|
+
let backendEstimatedFiles = [];
|
|
1446
|
+
let backendEstimatedEntities = 0;
|
|
1447
|
+
let frontendEstimatedCredits = 0;
|
|
1448
|
+
let frontendEstimatedFiles = [];
|
|
1449
|
+
let frontendEstimatedEntities = 0;
|
|
1387
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
|
+
};
|
|
1388
1466
|
try {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
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
|
+
}
|
|
1415
1495
|
const creditUsage = await apiClient.getCreditUsage(organizationId);
|
|
1416
1496
|
creditsRemaining = creditUsage.remaining;
|
|
1417
1497
|
estimateSpinner.stop("Credit estimate calculated");
|
|
1418
1498
|
} catch {
|
|
1419
1499
|
estimateSpinner.stop("Could not estimate credits (will be calculated on generation)");
|
|
1420
1500
|
}
|
|
1421
|
-
const
|
|
1501
|
+
const totalEstimatedCredits = backendEstimatedCredits + frontendEstimatedCredits;
|
|
1502
|
+
const totalEstimatedFiles = backendEstimatedFiles.length + frontendEstimatedFiles.length;
|
|
1503
|
+
const totalEstimatedEntities = backendEstimatedEntities + frontendEstimatedEntities;
|
|
1504
|
+
const hasEnoughCredits = totalEstimatedCredits === 0 || creditsRemaining >= totalEstimatedCredits;
|
|
1422
1505
|
console.log("");
|
|
1423
1506
|
console.log(chalk7.bold(" Generation Summary"));
|
|
1424
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"));
|
|
1425
1508
|
console.log(chalk7.gray(" Project:"), chalk7.white(project.name));
|
|
1426
|
-
console.log(chalk7.gray(" Template:"), chalk7.cyan(templateId));
|
|
1427
1509
|
console.log(chalk7.gray(" Namespace:"), chalk7.cyan(namespace));
|
|
1428
1510
|
console.log(chalk7.gray(" Directory:"), chalk7.cyan(`${safeName}/`));
|
|
1429
|
-
console.log(
|
|
1511
|
+
console.log(
|
|
1512
|
+
chalk7.gray(" Architecture:"),
|
|
1513
|
+
useContexts ? chalk7.cyan("Bounded Contexts") : chalk7.yellow("Flat Structure")
|
|
1514
|
+
);
|
|
1430
1515
|
if (hasMultipleDiagrams) {
|
|
1431
1516
|
const selectedCount = selectedDiagramIds.length;
|
|
1432
1517
|
const totalCount = diagrams.length;
|
|
@@ -1437,14 +1522,23 @@ async function createCommand(projectName, options) {
|
|
|
1437
1522
|
console.log(chalk7.gray(" Bounded Contexts:"), chalk7.cyan(`${selectedCount}/${totalCount} (${selectedNames})`));
|
|
1438
1523
|
}
|
|
1439
1524
|
}
|
|
1440
|
-
|
|
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) {
|
|
1441
1535
|
console.log("");
|
|
1442
|
-
console.log(chalk7.bold(
|
|
1536
|
+
console.log(chalk7.bold(` Backend Files (${backendTemplateId})`));
|
|
1443
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"));
|
|
1444
|
-
const
|
|
1445
|
-
const
|
|
1446
|
-
for (const category of
|
|
1447
|
-
const padding = " ".repeat(
|
|
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);
|
|
1448
1542
|
const countStr = category.count.toString().padStart(3, " ");
|
|
1449
1543
|
console.log(
|
|
1450
1544
|
chalk7.gray(` ${category.name}${padding}`),
|
|
@@ -1452,21 +1546,65 @@ async function createCommand(projectName, options) {
|
|
|
1452
1546
|
);
|
|
1453
1547
|
}
|
|
1454
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"));
|
|
1455
|
-
const
|
|
1456
|
-
const
|
|
1549
|
+
const subtotalPadding = " ".repeat(backendMaxNameLength - 8 + 2);
|
|
1550
|
+
const subtotalStr = backendEstimatedFiles.length.toString().padStart(3, " ");
|
|
1457
1551
|
console.log(
|
|
1458
|
-
chalk7.white(`
|
|
1459
|
-
chalk7.bold.cyan(`${
|
|
1552
|
+
chalk7.white(` Subtotal${subtotalPadding}`),
|
|
1553
|
+
chalk7.bold.cyan(`${subtotalStr} files`)
|
|
1460
1554
|
);
|
|
1461
|
-
|
|
1555
|
+
}
|
|
1556
|
+
if (frontendEstimatedFiles.length > 0) {
|
|
1557
|
+
console.log("");
|
|
1558
|
+
console.log(chalk7.bold(` Frontend Files (${frontendTemplateId})`));
|
|
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"));
|
|
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);
|
|
1564
|
+
const countStr = category.count.toString().padStart(3, " ");
|
|
1565
|
+
console.log(
|
|
1566
|
+
chalk7.gray(` ${category.name}${padding}`),
|
|
1567
|
+
chalk7.cyan(`${countStr} files`)
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
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"));
|
|
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"));
|
|
1581
|
+
console.log(
|
|
1582
|
+
chalk7.bold.white(" TOTAL "),
|
|
1583
|
+
chalk7.bold.green(`${totalEstimatedFiles.toString().padStart(3, " ")} files`)
|
|
1584
|
+
);
|
|
1585
|
+
console.log(chalk7.gray(" Entities:"), chalk7.cyan(totalEstimatedEntities));
|
|
1586
|
+
} else if (totalEstimatedFiles > 0) {
|
|
1587
|
+
console.log(chalk7.gray(" Entities:"), chalk7.cyan(totalEstimatedEntities));
|
|
1462
1588
|
}
|
|
1463
1589
|
console.log("");
|
|
1464
1590
|
console.log(chalk7.bold(" Credits"));
|
|
1465
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"));
|
|
1466
|
-
if (
|
|
1592
|
+
if (backendEstimatedCredits > 0) {
|
|
1593
|
+
console.log(
|
|
1594
|
+
chalk7.gray(" Backend:"),
|
|
1595
|
+
chalk7.yellow(`${backendEstimatedCredits} credits`)
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
if (frontendEstimatedCredits > 0) {
|
|
1599
|
+
console.log(
|
|
1600
|
+
chalk7.gray(" Frontend:"),
|
|
1601
|
+
chalk7.yellow(`${frontendEstimatedCredits} credits`)
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
if (totalEstimatedCredits > 0) {
|
|
1467
1605
|
console.log(
|
|
1468
|
-
chalk7.white(" Cost:"),
|
|
1469
|
-
hasEnoughCredits ? chalk7.bold.yellow(`${
|
|
1606
|
+
chalk7.white(" Total Cost:"),
|
|
1607
|
+
hasEnoughCredits ? chalk7.bold.yellow(`${totalEstimatedCredits} credits`) : chalk7.bold.red(`${totalEstimatedCredits} credits`)
|
|
1470
1608
|
);
|
|
1471
1609
|
}
|
|
1472
1610
|
console.log(
|
|
@@ -1476,12 +1614,12 @@ async function createCommand(projectName, options) {
|
|
|
1476
1614
|
console.log("");
|
|
1477
1615
|
if (!hasEnoughCredits) {
|
|
1478
1616
|
console.log(chalk7.red(" \u26A0 Not enough credits for this generation."));
|
|
1479
|
-
console.log(chalk7.gray(` Need ${
|
|
1617
|
+
console.log(chalk7.gray(` Need ${totalEstimatedCredits - creditsRemaining} more credits.
|
|
1480
1618
|
`));
|
|
1481
1619
|
process.exit(1);
|
|
1482
1620
|
}
|
|
1483
1621
|
const proceed = await p.confirm({
|
|
1484
|
-
message:
|
|
1622
|
+
message: totalEstimatedCredits > 0 ? `Proceed with generation? (~${totalEstimatedCredits} credits)` : "Proceed with generation?",
|
|
1485
1623
|
initialValue: true
|
|
1486
1624
|
});
|
|
1487
1625
|
if (p.isCancel(proceed) || !proceed) {
|
|
@@ -1492,47 +1630,68 @@ async function createCommand(projectName, options) {
|
|
|
1492
1630
|
dirSpinner.start(`Creating ${safeName}/...`);
|
|
1493
1631
|
await mkdir(projectDir, { recursive: true });
|
|
1494
1632
|
dirSpinner.stop(`Created ${safeName}/`);
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
// 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;
|
|
1520
1657
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
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
|
+
}
|
|
1523
1684
|
const writeSpinner = p.spinner();
|
|
1524
1685
|
writeSpinner.start("Writing files...");
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
path: `backend/${file.path}`
|
|
1528
|
-
}));
|
|
1529
|
-
await writeGeneratedFiles(organizedFiles, projectDir, false);
|
|
1530
|
-
writeSpinner.stop(`Wrote ${organizedFiles.length} files`);
|
|
1686
|
+
await writeGeneratedFiles(allGeneratedFiles, projectDir, false);
|
|
1687
|
+
writeSpinner.stop(`Wrote ${allGeneratedFiles.length} files`);
|
|
1531
1688
|
const configSpinner = p.spinner();
|
|
1532
1689
|
configSpinner.start("Creating config files...");
|
|
1533
1690
|
const projectConfig = createProjectConfig({
|
|
1534
1691
|
projectId,
|
|
1535
|
-
templateId,
|
|
1692
|
+
templateId: backendTemplateId || frontendTemplateId || "",
|
|
1693
|
+
backendTemplateId,
|
|
1694
|
+
frontendTemplateId,
|
|
1536
1695
|
templateVersion: "1.0.0",
|
|
1537
1696
|
// TODO: get from template
|
|
1538
1697
|
namespace,
|
|
@@ -1541,7 +1700,7 @@ async function createCommand(projectName, options) {
|
|
|
1541
1700
|
});
|
|
1542
1701
|
await saveProjectConfig(projectConfig, projectDir);
|
|
1543
1702
|
let manifest = createEmptyManifest("1.0.0");
|
|
1544
|
-
for (const file of
|
|
1703
|
+
for (const file of allGeneratedFiles) {
|
|
1545
1704
|
const hash = hashString(file.content);
|
|
1546
1705
|
manifest = setManifestFile(manifest, file.path, {
|
|
1547
1706
|
hash,
|
|
@@ -1566,13 +1725,21 @@ async function createCommand(projectName, options) {
|
|
|
1566
1725
|
console.log(chalk7.bold(" Project Created Successfully!"));
|
|
1567
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"));
|
|
1568
1727
|
console.log(chalk7.gray(" Directory:"), chalk7.cyan(safeName + "/"));
|
|
1569
|
-
|
|
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
|
+
}
|
|
1570
1737
|
console.log(chalk7.gray(" Config:"), chalk7.cyan(PROJECT_CONFIG_FILENAME));
|
|
1571
1738
|
console.log(chalk7.gray(" Manifest:"), chalk7.cyan(MANIFEST_FILENAME));
|
|
1572
|
-
if (
|
|
1739
|
+
if (totalCreditsUsed > 0) {
|
|
1573
1740
|
console.log("");
|
|
1574
|
-
console.log(chalk7.gray(" Credits used:"), chalk7.yellow(
|
|
1575
|
-
console.log(chalk7.gray(" Credits remaining:"), chalk7.green(
|
|
1741
|
+
console.log(chalk7.gray(" Credits used:"), chalk7.yellow(totalCreditsUsed));
|
|
1742
|
+
console.log(chalk7.gray(" Credits remaining:"), chalk7.green(totalCreditsRemaining));
|
|
1576
1743
|
}
|
|
1577
1744
|
p.outro(
|
|
1578
1745
|
chalk7.green("Project ready!") + "\n\n" + chalk7.gray(" Next steps:\n") + chalk7.cyan(` cd ${safeName}
|
|
@@ -2043,7 +2210,7 @@ async function findConflictFiles(dir) {
|
|
|
2043
2210
|
// src/index.ts
|
|
2044
2211
|
import "dotenv/config";
|
|
2045
2212
|
var program = new Command();
|
|
2046
|
-
program.name("aerocoding").description("AeroCoding CLI - Generate production-ready code from UML diagrams").version("0.1.
|
|
2213
|
+
program.name("aerocoding").description("AeroCoding CLI - Generate production-ready code from UML diagrams").version("0.1.28");
|
|
2047
2214
|
program.command("login").description("Authenticate with AeroCoding").action(loginCommand);
|
|
2048
2215
|
program.command("logout").description("Logout and clear stored credentials").action(logoutCommand);
|
|
2049
2216
|
program.command("whoami").description("Show current authenticated user").action(whoamiCommand);
|