aerocoding 0.1.26 → 0.1.28
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 +114 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1343,6 +1343,25 @@ async function createCommand(projectName, options) {
|
|
|
1343
1343
|
}
|
|
1344
1344
|
templateId = selectedTemplate;
|
|
1345
1345
|
}
|
|
1346
|
+
const diagrams = project.schema?.diagrams || [];
|
|
1347
|
+
const hasMultipleDiagrams = diagrams.length > 1;
|
|
1348
|
+
let selectedDiagramIds = diagrams.map((d) => d.id || d.name || "unknown");
|
|
1349
|
+
if (hasMultipleDiagrams) {
|
|
1350
|
+
const diagramChoices = await p.multiselect({
|
|
1351
|
+
message: "Which bounded contexts do you want to generate?",
|
|
1352
|
+
options: diagrams.map((d) => ({
|
|
1353
|
+
value: d.id || d.name || "unknown",
|
|
1354
|
+
label: `${d.name || "Unnamed"} (${d.entities?.length || 0} entities)`
|
|
1355
|
+
})),
|
|
1356
|
+
initialValues: diagrams.map((d) => d.id || d.name || "unknown"),
|
|
1357
|
+
required: true
|
|
1358
|
+
});
|
|
1359
|
+
if (p.isCancel(diagramChoices)) {
|
|
1360
|
+
p.cancel("Operation cancelled.");
|
|
1361
|
+
process.exit(0);
|
|
1362
|
+
}
|
|
1363
|
+
selectedDiagramIds = diagramChoices;
|
|
1364
|
+
}
|
|
1346
1365
|
const namespace = await p.text({
|
|
1347
1366
|
message: "Root namespace/package name",
|
|
1348
1367
|
placeholder: "MegaStore",
|
|
@@ -1359,10 +1378,34 @@ async function createCommand(projectName, options) {
|
|
|
1359
1378
|
p.cancel("Operation cancelled.");
|
|
1360
1379
|
process.exit(0);
|
|
1361
1380
|
}
|
|
1381
|
+
const archStyleChoice = await p.select({
|
|
1382
|
+
message: "Architecture style",
|
|
1383
|
+
options: [
|
|
1384
|
+
{
|
|
1385
|
+
value: "bounded-contexts",
|
|
1386
|
+
label: "Bounded Contexts",
|
|
1387
|
+
hint: "DDD-style: separate folders per module (recommended)"
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
value: "flat",
|
|
1391
|
+
label: "Flat Structure",
|
|
1392
|
+
hint: "All layers in single structure (simpler)"
|
|
1393
|
+
}
|
|
1394
|
+
],
|
|
1395
|
+
initialValue: "bounded-contexts"
|
|
1396
|
+
});
|
|
1397
|
+
if (p.isCancel(archStyleChoice)) {
|
|
1398
|
+
p.cancel("Operation cancelled.");
|
|
1399
|
+
process.exit(0);
|
|
1400
|
+
}
|
|
1401
|
+
const useContexts = archStyleChoice === "bounded-contexts";
|
|
1362
1402
|
const estimateSpinner = p.spinner();
|
|
1363
1403
|
estimateSpinner.start("Calculating credit cost...");
|
|
1364
1404
|
let estimatedCredits = 0;
|
|
1365
1405
|
let creditsRemaining = 0;
|
|
1406
|
+
let estimatedFiles = [];
|
|
1407
|
+
let estimatedEntities = 0;
|
|
1408
|
+
const estimateDiagramIds = selectedDiagramIds.length < diagrams.length ? selectedDiagramIds : void 0;
|
|
1366
1409
|
try {
|
|
1367
1410
|
const estimate = await apiClient.estimateCreditCost({
|
|
1368
1411
|
projectId,
|
|
@@ -1383,31 +1426,86 @@ async function createCommand(projectName, options) {
|
|
|
1383
1426
|
includeOutbox: true,
|
|
1384
1427
|
includeInbox: true
|
|
1385
1428
|
},
|
|
1386
|
-
useContexts
|
|
1429
|
+
useContexts,
|
|
1430
|
+
diagramIds: estimateDiagramIds
|
|
1387
1431
|
}
|
|
1388
1432
|
});
|
|
1389
1433
|
estimatedCredits = estimate.estimatedCredits;
|
|
1434
|
+
estimatedFiles = estimate.files || [];
|
|
1435
|
+
estimatedEntities = estimate.entities || 0;
|
|
1390
1436
|
const creditUsage = await apiClient.getCreditUsage(organizationId);
|
|
1391
1437
|
creditsRemaining = creditUsage.remaining;
|
|
1392
1438
|
estimateSpinner.stop("Credit estimate calculated");
|
|
1393
1439
|
} catch {
|
|
1394
1440
|
estimateSpinner.stop("Could not estimate credits (will be calculated on generation)");
|
|
1395
1441
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1442
|
+
const hasEnoughCredits = estimatedCredits === 0 || creditsRemaining >= estimatedCredits;
|
|
1443
|
+
console.log("");
|
|
1444
|
+
console.log(chalk7.bold(" Generation Summary"));
|
|
1445
|
+
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
|
+
console.log(chalk7.gray(" Project:"), chalk7.white(project.name));
|
|
1447
|
+
console.log(chalk7.gray(" Template:"), chalk7.cyan(templateId));
|
|
1448
|
+
console.log(chalk7.gray(" Namespace:"), chalk7.cyan(namespace));
|
|
1449
|
+
console.log(chalk7.gray(" Directory:"), chalk7.cyan(`${safeName}/`));
|
|
1450
|
+
console.log(
|
|
1451
|
+
chalk7.gray(" Architecture:"),
|
|
1452
|
+
useContexts ? chalk7.cyan("Bounded Contexts") : chalk7.yellow("Flat Structure")
|
|
1453
|
+
);
|
|
1454
|
+
if (hasMultipleDiagrams) {
|
|
1455
|
+
const selectedCount = selectedDiagramIds.length;
|
|
1456
|
+
const totalCount = diagrams.length;
|
|
1457
|
+
if (selectedCount === totalCount) {
|
|
1458
|
+
console.log(chalk7.gray(" Bounded Contexts:"), chalk7.cyan(`All (${totalCount})`));
|
|
1459
|
+
} else {
|
|
1460
|
+
const selectedNames = diagrams.filter((d) => selectedDiagramIds.includes(d.id || d.name || "unknown")).map((d) => d.name || "Unnamed").join(", ");
|
|
1461
|
+
console.log(chalk7.gray(" Bounded Contexts:"), chalk7.cyan(`${selectedCount}/${totalCount} (${selectedNames})`));
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (estimatedFiles.length > 0) {
|
|
1402
1465
|
console.log("");
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1466
|
+
console.log(chalk7.bold(" Files to Generate"));
|
|
1467
|
+
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);
|
|
1472
|
+
const countStr = category.count.toString().padStart(3, " ");
|
|
1473
|
+
console.log(
|
|
1474
|
+
chalk7.gray(` ${category.name}${padding}`),
|
|
1475
|
+
chalk7.cyan(`${countStr} files`)
|
|
1476
|
+
);
|
|
1407
1477
|
}
|
|
1478
|
+
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, " ");
|
|
1481
|
+
console.log(
|
|
1482
|
+
chalk7.white(` Total${totalPadding}`),
|
|
1483
|
+
chalk7.bold.cyan(`${totalStr} files`)
|
|
1484
|
+
);
|
|
1485
|
+
console.log(chalk7.gray(" Entities:"), chalk7.cyan(estimatedEntities));
|
|
1486
|
+
}
|
|
1487
|
+
console.log("");
|
|
1488
|
+
console.log(chalk7.bold(" Credits"));
|
|
1489
|
+
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) {
|
|
1491
|
+
console.log(
|
|
1492
|
+
chalk7.white(" Cost:"),
|
|
1493
|
+
hasEnoughCredits ? chalk7.bold.yellow(`${estimatedCredits} credits`) : chalk7.bold.red(`${estimatedCredits} credits`)
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
console.log(
|
|
1497
|
+
chalk7.white(" Available:"),
|
|
1498
|
+
hasEnoughCredits ? chalk7.bold.green(`${creditsRemaining} credits`) : chalk7.bold.red(`${creditsRemaining} credits (insufficient)`)
|
|
1499
|
+
);
|
|
1500
|
+
console.log("");
|
|
1501
|
+
if (!hasEnoughCredits) {
|
|
1502
|
+
console.log(chalk7.red(" \u26A0 Not enough credits for this generation."));
|
|
1503
|
+
console.log(chalk7.gray(` Need ${estimatedCredits - creditsRemaining} more credits.
|
|
1504
|
+
`));
|
|
1505
|
+
process.exit(1);
|
|
1408
1506
|
}
|
|
1409
1507
|
const proceed = await p.confirm({
|
|
1410
|
-
message: estimatedCredits > 0 ? `
|
|
1508
|
+
message: estimatedCredits > 0 ? `Proceed with generation? (~${estimatedCredits} credits)` : "Proceed with generation?",
|
|
1411
1509
|
initialValue: true
|
|
1412
1510
|
});
|
|
1413
1511
|
if (p.isCancel(proceed) || !proceed) {
|
|
@@ -1440,7 +1538,9 @@ async function createCommand(projectName, options) {
|
|
|
1440
1538
|
includeOutbox: true,
|
|
1441
1539
|
includeInbox: true
|
|
1442
1540
|
},
|
|
1443
|
-
useContexts
|
|
1541
|
+
useContexts,
|
|
1542
|
+
diagramIds: estimateDiagramIds
|
|
1543
|
+
// Filter by selected bounded contexts
|
|
1444
1544
|
}
|
|
1445
1545
|
});
|
|
1446
1546
|
genSpinner.succeed(chalk7.green(`Generated ${result.files?.length || 0} files`));
|
|
@@ -1967,7 +2067,7 @@ async function findConflictFiles(dir) {
|
|
|
1967
2067
|
// src/index.ts
|
|
1968
2068
|
import "dotenv/config";
|
|
1969
2069
|
var program = new Command();
|
|
1970
|
-
program.name("aerocoding").description("AeroCoding CLI - Generate production-ready code from UML diagrams").version("0.1.
|
|
2070
|
+
program.name("aerocoding").description("AeroCoding CLI - Generate production-ready code from UML diagrams").version("0.1.28");
|
|
1971
2071
|
program.command("login").description("Authenticate with AeroCoding").action(loginCommand);
|
|
1972
2072
|
program.command("logout").description("Logout and clear stored credentials").action(logoutCommand);
|
|
1973
2073
|
program.command("whoami").description("Show current authenticated user").action(whoamiCommand);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/auth/device-flow.ts","../src/auth/token-manager.ts","../src/api/client.ts","../src/commands/_shared/create-api-client.ts","../src/commands/_shared/unauthorized.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/create.ts","../src/utils/file-writer.ts","../src/manifest/index.ts","../src/manifest/types.ts","../src/manifest/hash-utils.ts","../src/merge/merger.ts","../src/merge/conflict-writer.ts","../src/config/project-config.ts","../src/utils/cloud-sync.ts","../src/commands/update.ts","../src/commands/resolve.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Command } from \"commander\";\r\nimport { loginCommand } from \"./commands/login.js\";\r\nimport { logoutCommand } from \"./commands/logout.js\";\r\nimport { whoamiCommand } from \"./commands/whoami.js\";\r\nimport { createCommand } from \"./commands/create.js\";\r\nimport { updateCommand } from \"./commands/update.js\";\r\nimport { resolveCommand } from \"./commands/resolve.js\";\r\nimport \"dotenv/config\";\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name(\"aerocoding\")\r\n .description(\"AeroCoding CLI - Generate production-ready code from UML diagrams\")\r\n .version(\"0.1.26\");\r\n\r\n// ============================================\r\n// Authentication Commands\r\n// ============================================\r\n\r\nprogram\r\n .command(\"login\")\r\n .description(\"Authenticate with AeroCoding\")\r\n .action(loginCommand);\r\n\r\nprogram\r\n .command(\"logout\")\r\n .description(\"Logout and clear stored credentials\")\r\n .action(logoutCommand);\r\n\r\nprogram\r\n .command(\"whoami\")\r\n .description(\"Show current authenticated user\")\r\n .action(whoamiCommand);\r\n\r\n// ============================================\r\n// Project Commands\r\n// ============================================\r\n\r\nprogram\r\n .command(\"create [name]\")\r\n .description(\"Create a new AeroCoding project with full architecture\")\r\n .option(\"-t, --template <id>\", \"Template ID (skip selection)\")\r\n .option(\"-p, --project <id>\", \"Project ID (skip selection)\")\r\n .option(\"-f, --force\", \"Overwrite existing directory without asking\")\r\n .action(createCommand);\r\n\r\nprogram\r\n .command(\"update\")\r\n .description(\"Update generated code incrementally (preserves your changes)\")\r\n .option(\"-f, --force\", \"Overwrite modified files without merging\")\r\n .option(\"-v, --verbose\", \"Show detailed file operations\")\r\n .option(\"--dry-run\", \"Preview changes without writing files\")\r\n .action(updateCommand);\r\n\r\nprogram\r\n .command(\"resolve\")\r\n .description(\"Clean up conflict files after manual resolution\")\r\n .option(\"-v, --verbose\", \"Show detailed resolution info\")\r\n .option(\"-a, --all\", \"Resolve all conflicts without confirmation\")\r\n .action(resolveCommand);\r\n\r\n// ============================================\r\n// Parse and Execute\r\n// ============================================\r\n\r\nprogram.parse();\r\n","import chalk from \"chalk\";\r\nimport { DeviceFlow } from \"../auth/device-flow.js\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\n\r\n/**\r\n * Login Command\r\n *\r\n * Authenticates user via OAuth Device Flow\r\n * Stores tokens securely in OS credential manager\r\n */\r\nexport async function loginCommand() {\r\n console.log(chalk.bold(\"\\nAeroCoding CLI Login\\n\"));\r\n\r\n const tokenManager = new TokenManager();\r\n\r\n // Check if already logged in\r\n const existingToken = await tokenManager.getAccessToken();\r\n if (existingToken) {\r\n const metadata = await tokenManager.getUserMetadata();\r\n console.log(\r\n chalk.yellow(\"Already logged in as:\"),\r\n chalk.white(metadata?.email || \"unknown\")\r\n );\r\n console.log(\r\n chalk.gray(\r\n \" Run 'aerocoding logout' to login with a different account\\n\"\r\n )\r\n );\r\n return;\r\n }\r\n\r\n try {\r\n // Initiate device flow\r\n const deviceFlow = new DeviceFlow();\r\n const tokens = await deviceFlow.initiateAuth();\r\n\r\n // Get user info\r\n const apiClient = createApiClientWithAutoLogout(\r\n tokens.access_token,\r\n tokenManager\r\n );\r\n let user;\r\n try {\r\n user = await apiClient.getCurrentUser();\r\n } catch (error: any) {\r\n if (error.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n }\r\n throw error;\r\n }\r\n\r\n // Save tokens\r\n await tokenManager.saveTokens(tokens.access_token, tokens.refresh_token, {\r\n id: user.id,\r\n email: user.email,\r\n name: user.name || undefined,\r\n tier: user.tier,\r\n });\r\n\r\n console.log(\"\");\r\n console.log(\r\n chalk.green(\"Successfully logged in as:\"),\r\n chalk.white(user.email)\r\n );\r\n console.log(chalk.gray(\" Run 'aerocoding whoami' to verify\\n\"));\r\n } catch (error: any) {\r\n console.error(\r\n chalk.red(\"\\nLogin failed:\"),\r\n error.message || \"Unknown error\"\r\n );\r\n process.exit(1);\r\n }\r\n}\r\n","import axios from \"axios\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport open from \"open\";\r\n\r\nconst API_URL = process.env.API_URL || \"https://aerocoding.dev\";\r\nconst MAX_POLL_TIME = 15 * 60 * 1000; // 15 minutes\r\n\r\ninterface DeviceAuthResponse {\r\n device_code: string;\r\n user_code: string;\r\n confirmation_code: string;\r\n verification_uri: string;\r\n verification_uri_complete: string;\r\n expires_in: number;\r\n interval: number;\r\n}\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token: string;\r\n token_type: string;\r\n expires_in: number;\r\n}\r\n\r\n/**\r\n * DeviceFlow\r\n *\r\n * Implements OAuth 2.0 Device Authorization Grant (RFC 8628)\r\n * Used for CLI authentication without browser-based redirects\r\n */\r\nexport class DeviceFlow {\r\n /**\r\n * Initiate the complete device authorization flow\r\n */\r\n async initiateAuth(): Promise<TokenResponse> {\r\n // Step 1: Request device code\r\n const deviceAuth = await this.requestDeviceCode();\r\n\r\n // Step 2: Display user code and open browser\r\n this.displayUserCode(deviceAuth);\r\n await this.openBrowser(deviceAuth.verification_uri);\r\n\r\n // Step 3: Poll for authorization\r\n const tokens = await this.pollForToken(deviceAuth);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Step 1: Request device code from server\r\n */\r\n private async requestDeviceCode(): Promise<DeviceAuthResponse> {\r\n try {\r\n const response = await axios.post(`${API_URL}/api/device/authorize`, {\r\n client_id: \"aerocoding-cli\",\r\n scope: \"generate:code projects:read\",\r\n });\r\n\r\n return response.data;\r\n } catch (error: any) {\r\n console.error(chalk.red(\"Failed to initiate device authorization\"));\r\n if (error.response) {\r\n console.error(\r\n chalk.red(`Error: ${error.response.data.error_description}`)\r\n );\r\n }\r\n throw new Error(\"Failed to initiate device authorization\");\r\n }\r\n }\r\n\r\n /**\r\n * Step 2: Display user code and instructions\r\n */\r\n private displayUserCode(auth: DeviceAuthResponse): void {\r\n console.log(\"\\n\");\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(chalk.bold.white(\" AeroCoding CLI - Device Activation\"));\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(\"\");\r\n console.log(chalk.white(\" 1. Open this URL in your browser:\"));\r\n console.log(chalk.cyan.bold(` ${auth.verification_uri}`));\r\n console.log(\"\");\r\n console.log(chalk.white(\" 2. Enter this code:\"));\r\n console.log(chalk.green.bold(` ${auth.user_code}`));\r\n console.log(\"\");\r\n console.log(\r\n chalk.gray(` Code expires in ${auth.expires_in / 60} minutes`)\r\n );\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(\"\");\r\n }\r\n\r\n /**\r\n * Step 2.5: Open browser automatically\r\n */\r\n private async openBrowser(url: string): Promise<void> {\r\n try {\r\n await open(url);\r\n console.log(chalk.gray(\" Opening browser...\"));\r\n } catch {\r\n console.log(chalk.yellow(\" Could not open browser automatically\"));\r\n console.log(chalk.gray(\" Please open the URL manually\\n\"));\r\n }\r\n }\r\n\r\n /**\r\n * Step 3: Poll for token\r\n */\r\n private async pollForToken(auth: DeviceAuthResponse): Promise<TokenResponse> {\r\n const spinner = ora({\r\n text: \"Waiting for authorization...\",\r\n color: \"cyan\",\r\n }).start();\r\n\r\n const startTime = Date.now();\r\n let currentInterval = auth.interval * 1000;\r\n\r\n while (true) {\r\n // Check timeout\r\n if (Date.now() - startTime > MAX_POLL_TIME) {\r\n spinner.fail(chalk.red(\"Authorization timeout\"));\r\n throw new Error(\"Device authorization timed out\");\r\n }\r\n\r\n try {\r\n const response = await axios.post(`${API_URL}/api/device/token`, {\r\n device_code: auth.device_code,\r\n client_id: \"aerocoding-cli\",\r\n });\r\n\r\n spinner.succeed(chalk.green(\"Successfully authenticated!\"));\r\n return response.data;\r\n } catch (error: any) {\r\n const errorCode = error.response?.data?.error;\r\n const errorDescription = error.response?.data?.error_description;\r\n\r\n if (errorCode === \"authorization_pending\") {\r\n // Keep polling\r\n await this.sleep(currentInterval);\r\n continue;\r\n }\r\n\r\n if (errorCode === \"slow_down\") {\r\n // Increase poll interval by 5 seconds\r\n currentInterval += 5000;\r\n spinner.text = \"Polling... (slowed down to avoid spam)\";\r\n await this.sleep(currentInterval);\r\n continue;\r\n }\r\n\r\n if (errorCode === \"expired_token\") {\r\n spinner.fail(chalk.red(\"Authorization code expired\"));\r\n throw new Error(\"Device code expired. Please try again.\");\r\n }\r\n\r\n if (errorCode === \"access_denied\") {\r\n spinner.fail(chalk.red(\"Authorization denied\"));\r\n throw new Error(\"You denied the authorization request\");\r\n }\r\n\r\n // Unknown error\r\n spinner.fail(chalk.red(\"Authorization failed\"));\r\n console.error(\r\n chalk.red(`Error: ${errorDescription || \"Unknown error\"}`)\r\n );\r\n throw new Error(errorDescription || \"Unknown error\");\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Helper: Sleep for specified milliseconds\r\n */\r\n private sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n}\r\n","import { Entry } from \"@napi-rs/keyring\";\r\nimport { createClient, SupabaseClient } from \"@supabase/supabase-js\";\r\n\r\nconst SERVICE_NAME = \"aerocoding-cli\";\r\n\r\n// Public Supabase credentials (anon key is safe to expose)\r\nconst SUPABASE_URL = \"https://peqpttkvdpjgmduzacwl.supabase.co\";\r\nconst SUPABASE_ANON_KEY = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBlcXB0dGt2ZHBqZ21kdXphY3dsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjQyNjUxNzMsImV4cCI6MjA3OTg0MTE3M30.WAzqgZusGoOEHxidfHc1e4daBglG4DJG5LOXbqldWQA\";\r\n\r\ninterface UserMetadata {\r\n id: string;\r\n email: string;\r\n name?: string;\r\n tier?: string;\r\n}\r\n\r\n/**\r\n * Helper functions for keyring operations using Entry class\r\n */\r\nfunction getPassword(service: string, account: string): string | null {\r\n try {\r\n const entry = new Entry(service, account);\r\n return entry.getPassword();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction setPassword(service: string, account: string, password: string): void {\r\n const entry = new Entry(service, account);\r\n entry.setPassword(password);\r\n}\r\n\r\nfunction deletePassword(service: string, account: string): void {\r\n try {\r\n const entry = new Entry(service, account);\r\n entry.deletePassword();\r\n } catch {\r\n // Ignore if entry doesn't exist\r\n }\r\n}\r\n\r\n/**\r\n * TokenManager\r\n *\r\n * Manages secure storage and automatic refresh of authentication tokens\r\n * Uses OS-level credential managers (Keychain/Credential Manager/Secret Service)\r\n */\r\nexport class TokenManager {\r\n private supabase: SupabaseClient;\r\n\r\n constructor() {\r\n this.supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {\r\n auth: {\r\n autoRefreshToken: false,\r\n persistSession: false,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get access token, automatically refreshing if expired\r\n */\r\n async getAccessToken(): Promise<string | null> {\r\n try {\r\n let accessToken = getPassword(SERVICE_NAME, \"access_token\");\r\n\r\n if (!accessToken) {\r\n return null;\r\n }\r\n\r\n // Check if expired\r\n if (this.isTokenExpired(accessToken)) {\r\n accessToken = await this.refreshTokens();\r\n }\r\n\r\n return accessToken;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Refresh tokens using stored refresh token\r\n */\r\n private async refreshTokens(): Promise<string | null> {\r\n try {\r\n const refreshToken = getPassword(SERVICE_NAME, \"refresh_token\");\r\n\r\n if (!refreshToken) {\r\n throw new Error(\"No refresh token available\");\r\n }\r\n\r\n const { data, error } = await this.supabase.auth.refreshSession({\r\n refresh_token: refreshToken,\r\n });\r\n\r\n if (error || !data.session) {\r\n throw new Error(\"Failed to refresh session\");\r\n }\r\n\r\n // Store new tokens (single-use refresh token rotation)\r\n setPassword(SERVICE_NAME, \"access_token\", data.session.access_token);\r\n setPassword(SERVICE_NAME, \"refresh_token\", data.session.refresh_token);\r\n\r\n return data.session.access_token;\r\n } catch {\r\n await this.logout();\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Check if JWT token is expired (or expires in < 5 min)\r\n */\r\n private isTokenExpired(token: string): boolean {\r\n try {\r\n const payload = JSON.parse(\r\n Buffer.from(token.split(\".\")[1]!, \"base64\").toString()\r\n );\r\n const expiresAt = payload.exp * 1000;\r\n const now = Date.now();\r\n\r\n // Refresh 5 minutes before expiration\r\n return expiresAt - now < 5 * 60 * 1000;\r\n } catch {\r\n return true; // Treat invalid tokens as expired\r\n }\r\n }\r\n\r\n /**\r\n * Save tokens and user metadata after successful login\r\n */\r\n async saveTokens(\r\n accessToken: string,\r\n refreshToken: string,\r\n user: UserMetadata\r\n ): Promise<void> {\r\n setPassword(SERVICE_NAME, \"access_token\", accessToken);\r\n setPassword(SERVICE_NAME, \"refresh_token\", refreshToken);\r\n setPassword(SERVICE_NAME, \"user_metadata\", JSON.stringify(user));\r\n }\r\n\r\n /**\r\n * Get stored user metadata\r\n */\r\n async getUserMetadata(): Promise<UserMetadata | null> {\r\n try {\r\n const metadata = getPassword(SERVICE_NAME, \"user_metadata\");\r\n return metadata ? JSON.parse(metadata) : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Logout - clear all stored credentials\r\n */\r\n async logout(): Promise<void> {\r\n try {\r\n deletePassword(SERVICE_NAME, \"access_token\");\r\n deletePassword(SERVICE_NAME, \"refresh_token\");\r\n deletePassword(SERVICE_NAME, \"user_metadata\");\r\n } catch (error) {\r\n // Ignore errors during logout\r\n }\r\n }\r\n\r\n /**\r\n * Check if user is currently authenticated\r\n */\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await this.getAccessToken();\r\n return token !== null;\r\n }\r\n}\r\n","import axios, { AxiosInstance } from \"axios\";\r\n\r\n// Production API URL (can be overridden via API_URL env for local dev)\r\nconst API_URL = process.env.API_URL || \"https://aerocoding.dev\";\r\n\r\ninterface User {\r\n id: string;\r\n email: string;\r\n name: string | null;\r\n tier: string;\r\n}\r\n\r\ninterface Organization {\r\n id: string;\r\n name: string;\r\n slug: string;\r\n planTier: string;\r\n}\r\n\r\ninterface Project {\r\n id: string;\r\n name: string;\r\n slug: string;\r\n schema: any;\r\n organizationId: string;\r\n backendFramework?: string;\r\n frontendFramework?: string;\r\n createdAt: string;\r\n updatedAt: string;\r\n}\r\n\r\ninterface GeneratePayload {\r\n projectId: string;\r\n // NEW: Use templateId for full architecture generation\r\n templateId?: string;\r\n // Legacy: Use targets for simple generation\r\n targets?: string[];\r\n options?: {\r\n includeValidations?: boolean;\r\n includeComments?: boolean;\r\n includeAnnotations?: boolean;\r\n includeLogging?: boolean;\r\n includeTesting?: boolean;\r\n outputDir?: string;\r\n backendPreset?: string;\r\n frontendPreset?: string;\r\n backendLayers?: string[];\r\n frontendLayers?: string[];\r\n validationLib?: string;\r\n // NEW: Feature flags for template generation\r\n featureFlags?: Record<string, boolean>;\r\n // Architecture style: bounded-contexts vs flat\r\n useContexts?: boolean;\r\n // Filter by diagram/bounded context IDs\r\n diagramIds?: string[];\r\n };\r\n}\r\n\r\ninterface GeneratedFile {\r\n path: string;\r\n content: string;\r\n language: string;\r\n entityId?: string;\r\n}\r\n\r\ninterface GenerateResult {\r\n files: GeneratedFile[];\r\n stats?: {\r\n totalFiles?: number;\r\n totalEntities?: number;\r\n languages?: string[];\r\n };\r\n cliCommand?: string;\r\n warnings?: string[];\r\n creditsUsed?: number;\r\n creditsRemaining?: number;\r\n}\r\n\r\ninterface CreditUsage {\r\n used: number;\r\n limit: number;\r\n bonusCredits: number;\r\n remaining: number;\r\n}\r\n\r\ninterface ArchitectureLayer {\r\n id: string;\r\n name: string;\r\n category: string;\r\n description?: string;\r\n}\r\n\r\ninterface Architecture {\r\n id: string;\r\n name: string;\r\n description: string;\r\n layers: ArchitectureLayer[];\r\n}\r\n\r\n// New Template Registry Types\r\ninterface TemplateMetadata {\r\n id: string;\r\n name: string;\r\n description: string;\r\n category: \"backend\" | \"frontend\" | \"database\" | \"infra\";\r\n language: string;\r\n framework: string;\r\n tier: \"starter\" | \"standard\" | \"enterprise\";\r\n tags: string[];\r\n version: string;\r\n author: string;\r\n isLegacy?: boolean;\r\n isOfficial?: boolean;\r\n isPremium?: boolean;\r\n /** Architecture style: \"bounded-contexts\" for DDD modules, \"flat\" for single structure */\r\n architectureStyle?: \"bounded-contexts\" | \"flat\";\r\n}\r\n\r\ninterface TemplateLayer {\r\n id: string;\r\n name: string;\r\n description: string;\r\n category: string;\r\n enabled: boolean;\r\n}\r\n\r\ninterface TemplateFeatureFlag {\r\n id: string;\r\n name: string;\r\n label: string;\r\n description?: string;\r\n defaultValue: boolean;\r\n}\r\n\r\ninterface FullTemplate extends TemplateMetadata {\r\n layers: TemplateLayer[];\r\n featureFlags: TemplateFeatureFlag[];\r\n enabledModules: string[];\r\n}\r\n\r\ninterface TemplateFilter {\r\n category?: \"backend\" | \"frontend\" | \"database\" | \"infra\";\r\n language?: string;\r\n framework?: string;\r\n tier?: \"starter\" | \"standard\" | \"enterprise\";\r\n tags?: string[];\r\n}\r\n\r\ninterface TemplateSearchResult {\r\n templates: TemplateMetadata[];\r\n total: number;\r\n page: number;\r\n pageSize: number;\r\n}\r\n\r\ninterface TemplateCombination {\r\n id: string;\r\n name: string;\r\n description: string;\r\n backend: string;\r\n frontend: string;\r\n sharedTypes?: boolean;\r\n apiContract?: \"rest\" | \"graphql\" | \"grpc\";\r\n}\r\n\r\ninterface CreditEstimate {\r\n estimatedCredits: number;\r\n totalFiles: number;\r\n files: string[];\r\n entities: number;\r\n}\r\n\r\ninterface EstimatePayload {\r\n projectId: string;\r\n // Template mode (new)\r\n templateId?: string;\r\n // Legacy targets mode\r\n targets?: string[];\r\n options?: {\r\n outputDir?: string;\r\n backendPreset?: string;\r\n frontendPreset?: string;\r\n backendLayers?: string[];\r\n frontendLayers?: string[];\r\n featureFlags?: Record<string, boolean>;\r\n // Architecture style: bounded-contexts vs flat\r\n useContexts?: boolean;\r\n // Filter by diagram/bounded context IDs\r\n diagramIds?: string[];\r\n };\r\n}\r\n\r\n/**\r\n * ApiClient\r\n *\r\n * Authenticated HTTP client for AeroCoding API\r\n * All requests include Bearer token authentication\r\n */\r\nexport class ApiClient {\r\n private client: AxiosInstance;\r\n\r\n constructor(\r\n accessToken: string,\r\n options?: {\r\n onUnauthorized?: () => Promise<void> | void;\r\n }\r\n ) {\r\n this.client = axios.create({\r\n baseURL: API_URL,\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"X-Requested-With\": \"XMLHttpRequest\", // Required for CSRF validation bypass\r\n },\r\n timeout: 30000, // 30 seconds\r\n });\r\n\r\n this.client.interceptors.response.use(\r\n (response) => response,\r\n async (error) => {\r\n if (error?.response?.status === 401) {\r\n await options?.onUnauthorized?.();\r\n }\r\n\r\n return Promise.reject(error);\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * Get current authenticated user\r\n */\r\n async getCurrentUser(): Promise<User> {\r\n const response = await this.client.get(\"/api/user/me\");\r\n return response.data;\r\n }\r\n\r\n /**\r\n * List user's organizations\r\n */\r\n async listOrganizations(): Promise<Organization[]> {\r\n const response = await this.client.get(\"/api/organizations\");\r\n return response.data;\r\n }\r\n\r\n /**\r\n * List user's projects\r\n */\r\n async listProjects(organizationId?: string): Promise<Project[]> {\r\n const response = await this.client.get(\"/api/projects\", {\r\n params: { organizationId },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get project by ID\r\n */\r\n async getProject(projectId: string): Promise<Project> {\r\n const response = await this.client.get(`/api/projects/${projectId}`);\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Generate code from project schema\r\n */\r\n async generateCode(payload: GeneratePayload): Promise<GenerateResult> {\r\n const response = await this.client.post(\"/api/generate\", payload);\r\n return response.data.data;\r\n }\r\n\r\n /**\r\n * Get credit usage for organization\r\n */\r\n async getCreditUsage(organizationId: string): Promise<CreditUsage> {\r\n const response = await this.client.get(\"/api/credits/usage\", {\r\n params: { organizationId },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get available architectures for a framework\r\n */\r\n async getArchitectures(framework: string): Promise<Architecture[]> {\r\n const response = await this.client.get(\"/api/architectures\", {\r\n params: { framework },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Estimate credit cost for a generation request\r\n */\r\n async estimateCreditCost(payload: EstimatePayload): Promise<CreditEstimate> {\r\n const response = await this.client.post(\"/api/generate/estimate\", payload);\r\n return response.data.data;\r\n }\r\n\r\n // ============================================\r\n // Template Registry API\r\n // ============================================\r\n\r\n /**\r\n * Search templates with filters\r\n */\r\n async getTemplates(filter: TemplateFilter = {}): Promise<TemplateSearchResult> {\r\n const params = new URLSearchParams();\r\n if (filter.category) params.set(\"category\", filter.category);\r\n if (filter.language) params.set(\"language\", filter.language);\r\n if (filter.framework) params.set(\"framework\", filter.framework);\r\n if (filter.tier) params.set(\"tier\", filter.tier);\r\n if (filter.tags?.length) params.set(\"tags\", filter.tags.join(\",\"));\r\n\r\n const response = await this.client.get(`/api/templates?${params.toString()}`);\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get full template by ID (includes layers and feature flags)\r\n */\r\n async getTemplate(id: string): Promise<FullTemplate> {\r\n const response = await this.client.get(`/api/templates/${id}?full=true`);\r\n return response.data.template;\r\n }\r\n\r\n /**\r\n * Get template combinations (backend + frontend pairs)\r\n */\r\n async getTemplateCombinations(): Promise<TemplateCombination[]> {\r\n const response = await this.client.get(\"/api/templates/combinations\");\r\n return response.data.combinations;\r\n }\r\n\r\n /**\r\n * Get templates compatible with a given template\r\n */\r\n async getCompatibleTemplates(templateId: string): Promise<TemplateMetadata[]> {\r\n const response = await this.client.get(`/api/templates/${templateId}?compatible=true`);\r\n return response.data.compatible || [];\r\n }\r\n\r\n // ============================================\r\n // Manifest Cloud Sync API\r\n // ============================================\r\n\r\n /**\r\n * Get manifest from cloud storage\r\n * @returns Manifest or null if not found\r\n */\r\n async getManifest(projectId: string): Promise<CloudManifest | null> {\r\n try {\r\n const response = await this.client.get(`/api/projects/${projectId}/manifest`);\r\n return response.data;\r\n } catch (error: any) {\r\n if (error?.response?.status === 404) {\r\n return null;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Save manifest to cloud storage\r\n */\r\n async saveManifest(\r\n projectId: string,\r\n manifest: CloudManifest\r\n ): Promise<{ success: boolean; fileCount: number; removedPaths: number }> {\r\n const response = await this.client.put(\r\n `/api/projects/${projectId}/manifest`,\r\n manifest\r\n );\r\n return response.data;\r\n }\r\n}\r\n\r\n// ============================================\r\n// Cloud Manifest Types\r\n// ============================================\r\n\r\nexport interface CloudManifestFileEntry {\r\n hash: string;\r\n mtime: number;\r\n size: number;\r\n entityId?: string;\r\n type?: \"entity\" | \"usecase\" | \"repository\" | \"controller\" | \"dto\" | \"config\" | \"test\" | \"other\";\r\n contextName?: string;\r\n}\r\n\r\nexport interface CloudManifest {\r\n version: string;\r\n lastSync?: string;\r\n templateVersion?: string;\r\n files: Record<string, CloudManifestFileEntry>;\r\n}\r\n","import { ApiClient } from \"../../api/client.js\";\r\nimport { TokenManager } from \"../../auth/token-manager.js\";\r\n\r\nexport function createApiClientWithAutoLogout(\r\n accessToken: string,\r\n tokenManager: TokenManager\r\n): ApiClient {\r\n return new ApiClient(accessToken, {\r\n onUnauthorized: async () => {\r\n await tokenManager.logout();\r\n },\r\n });\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../../auth/token-manager.js\";\r\n\r\nexport async function handleUnauthorized(\r\n tokenManager: TokenManager\r\n): Promise<never> {\r\n await tokenManager.logout();\r\n\r\n console.error(\r\n chalk.yellow(\r\n \" Your session is invalid or expired. You have been logged out.\"\r\n )\r\n );\r\n console.error(chalk.gray(\" Run 'aerocoding login' to authenticate.\"));\r\n\r\n process.exit(1);\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\n\r\n/**\r\n * Logout Command\r\n *\r\n * Clears stored credentials from OS credential manager\r\n */\r\nexport async function logoutCommand() {\r\n const tokenManager = new TokenManager();\r\n\r\n const metadata = await tokenManager.getUserMetadata();\r\n if (!metadata) {\r\n console.log(chalk.yellow(\"Not logged in\"));\r\n return;\r\n }\r\n\r\n const email = metadata.email;\r\n\r\n await tokenManager.logout();\r\n\r\n console.log(chalk.green(\"Logged out successfully\"));\r\n console.log(chalk.gray(` Cleared credentials for ${email}\\n`));\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\n\r\n/**\r\n * Whoami Command\r\n *\r\n * Shows current authenticated user information\r\n */\r\nexport async function whoamiCommand() {\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n console.log(chalk.red(\"Not logged in\"));\r\n console.log(chalk.gray(\" Run 'aerocoding login' to authenticate\\n\"));\r\n return;\r\n }\r\n\r\n try {\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n const user = await apiClient.getCurrentUser();\r\n\r\n console.log(\"\");\r\n console.log(chalk.white(\"Logged in as:\"), chalk.cyan.bold(user.email));\r\n if (user.name) {\r\n console.log(chalk.gray(\" Name:\"), user.name);\r\n }\r\n console.log(\"\");\r\n } catch (error: any) {\r\n console.error(chalk.red(\"Failed to get user info\"));\r\n if (error.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n","import * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport { mkdir, access } from \"node:fs/promises\";\r\nimport { resolve } from \"node:path\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\nimport { writeGeneratedFiles } from \"../utils/file-writer.js\";\r\nimport {\r\n createProjectConfig,\r\n saveProjectConfig,\r\n PROJECT_CONFIG_FILENAME,\r\n} from \"../config/project-config.js\";\r\nimport {\r\n createEmptyManifest,\r\n writeManifest,\r\n setManifestFile,\r\n hashString,\r\n MANIFEST_FILENAME,\r\n type AeroManifest,\r\n} from \"../manifest/index.js\";\r\nimport { syncToCloud } from \"../utils/cloud-sync.js\";\r\n\r\ninterface CreateOptions {\r\n template?: string;\r\n project?: string;\r\n force?: boolean;\r\n}\r\n\r\n/**\r\n * Create Command\r\n *\r\n * Creates a new AeroCoding project with full architecture generation.\r\n * Combines init + generate into a single command for the meta-framework approach.\r\n *\r\n * Flow:\r\n * 1. Interactive setup (select org, project, template)\r\n * 2. Infer directory name from project (or use provided name)\r\n * 3. Generate full architecture\r\n * 4. Create aerocoding.json + aerocoding-manifest.json\r\n */\r\nexport async function createCommand(projectName: string | undefined, options: CreateOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Create \"));\r\n\r\n // 1. Check authentication first\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n p.cancel(\"Not logged in. Run 'aerocoding login' first.\");\r\n process.exit(1);\r\n }\r\n\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n\r\n try {\r\n // 2. Select organization\r\n const orgSpinner = p.spinner();\r\n orgSpinner.start(\"Loading organizations...\");\r\n\r\n const organizations = await apiClient.listOrganizations();\r\n orgSpinner.stop(\"Organizations loaded\");\r\n\r\n if (organizations.length === 0) {\r\n p.cancel(\"No organizations found. Create one on aerocoding.dev first.\");\r\n process.exit(1);\r\n }\r\n\r\n let organizationId: string;\r\n\r\n if (organizations.length === 1 && organizations[0]) {\r\n organizationId = organizations[0].id;\r\n p.log.info(`Organization: ${organizations[0].name}`);\r\n } else {\r\n const selectedOrg = await p.select({\r\n message: \"Select organization\",\r\n options: organizations.map((org) => ({\r\n value: org.id,\r\n label: org.name,\r\n hint: org.planTier.toUpperCase(),\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedOrg)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n organizationId = selectedOrg as string;\r\n }\r\n\r\n // 3. Select project (or use provided --project)\r\n let projectId = options.project;\r\n\r\n if (!projectId) {\r\n const spinner = p.spinner();\r\n spinner.start(\"Loading projects...\");\r\n\r\n const projects = await apiClient.listProjects(organizationId);\r\n spinner.stop(\"Projects loaded\");\r\n\r\n if (projects.length === 0) {\r\n p.cancel(\"No projects in this organization. Create one on aerocoding.dev first.\");\r\n process.exit(1);\r\n }\r\n\r\n const selectedProject = await p.select({\r\n message: \"Select project to generate from\",\r\n options: projects.map((proj) => ({\r\n value: proj.id,\r\n label: proj.name,\r\n hint: [proj.backendFramework, proj.frontendFramework].filter(Boolean).join(\" + \"),\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedProject)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n projectId = selectedProject as string;\r\n }\r\n\r\n // 4. Fetch project details\r\n const projectSpinner = p.spinner();\r\n projectSpinner.start(\"Fetching project details...\");\r\n const project = await apiClient.getProject(projectId);\r\n projectSpinner.stop(`Project: ${project.name}`);\r\n\r\n // 5. Determine directory name (from argument or project name)\r\n const dirName = projectName || project.name;\r\n const safeName = dirName\r\n .toLowerCase()\r\n .replace(/[^a-z0-9-]/g, \"-\")\r\n .replace(/-+/g, \"-\")\r\n .replace(/^-|-$/g, \"\");\r\n\r\n if (!safeName) {\r\n p.cancel(\"Invalid project name. Use alphanumeric characters and hyphens.\");\r\n process.exit(1);\r\n }\r\n\r\n const projectDir = resolve(process.cwd(), safeName);\r\n\r\n // Check if directory already exists\r\n try {\r\n await access(projectDir);\r\n if (!options.force) {\r\n const overwrite = await p.confirm({\r\n message: `Directory '${safeName}' already exists. Overwrite?`,\r\n initialValue: false,\r\n });\r\n\r\n if (p.isCancel(overwrite) || !overwrite) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n } catch {\r\n // Directory doesn't exist, good\r\n }\r\n\r\n // 5. Select template\r\n let templateId = options.template;\r\n\r\n if (!templateId) {\r\n const templateSpinner = p.spinner();\r\n templateSpinner.start(\"Loading templates...\");\r\n\r\n // Get backend templates if project has backend\r\n const templateResult = await apiClient.getTemplates({\r\n category: \"backend\",\r\n language: project.backendFramework || undefined,\r\n });\r\n\r\n templateSpinner.stop(\"Templates loaded\");\r\n\r\n if (templateResult.templates.length === 0) {\r\n p.cancel(\"No templates available for this project's framework.\");\r\n process.exit(1);\r\n }\r\n\r\n const selectedTemplate = await p.select({\r\n message: \"Select architecture template\",\r\n options: templateResult.templates.map((tmpl) => ({\r\n value: tmpl.id,\r\n label: tmpl.name,\r\n hint: tmpl.description || `${tmpl.tier} tier`,\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedTemplate)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n templateId = selectedTemplate as string;\r\n }\r\n\r\n // 6. Get namespace\r\n const namespace = await p.text({\r\n message: \"Root namespace/package name\",\r\n placeholder: \"MegaStore\",\r\n initialValue: toPascalCase(project.name),\r\n validate: (value) => {\r\n if (!value || value.trim() === \"\") return \"Namespace is required\";\r\n if (!/^[A-Za-z][A-Za-z0-9]*$/.test(value)) {\r\n return \"Namespace must start with a letter and contain only alphanumeric characters\";\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (p.isCancel(namespace)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n // 7. Get credit estimate BEFORE confirmation\r\n const estimateSpinner = p.spinner();\r\n estimateSpinner.start(\"Calculating credit cost...\");\r\n\r\n let estimatedCredits = 0;\r\n let creditsRemaining = 0;\r\n\r\n try {\r\n const estimate = await apiClient.estimateCreditCost({\r\n projectId,\r\n templateId,\r\n options: {\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: true,\r\n includeReactions: true,\r\n includeOutbox: true,\r\n includeInbox: true,\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n estimatedCredits = estimate.estimatedCredits;\r\n \r\n // Get remaining credits\r\n const creditUsage = await apiClient.getCreditUsage(organizationId);\r\n creditsRemaining = creditUsage.remaining;\r\n \r\n estimateSpinner.stop(\"Credit estimate calculated\");\r\n } catch {\r\n estimateSpinner.stop(\"Could not estimate credits (will be calculated on generation)\");\r\n }\r\n\r\n // 8. Show summary with credit estimate\r\n p.log.step(chalk.bold(\"Configuration Summary:\"));\r\n p.log.info(` Directory: ${safeName}/`);\r\n p.log.info(` Project: ${project.name}`);\r\n p.log.info(` Template: ${templateId}`);\r\n p.log.info(` Namespace: ${namespace}`);\r\n \r\n if (estimatedCredits > 0) {\r\n console.log(\"\");\r\n p.log.info(chalk.yellow(` Estimated Credits: ~${estimatedCredits}`));\r\n p.log.info(chalk.gray(` Your Balance: ${creditsRemaining}`));\r\n \r\n if (creditsRemaining < estimatedCredits) {\r\n p.log.warn(chalk.red(\" ⚠ You may not have enough credits for this generation.\"));\r\n }\r\n }\r\n\r\n const proceed = await p.confirm({\r\n message: estimatedCredits > 0 \r\n ? `Generate project (~${estimatedCredits} credits)?`\r\n : \"Create project with these settings?\",\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n // 8. Create directory\r\n const dirSpinner = p.spinner();\r\n dirSpinner.start(`Creating ${safeName}/...`);\r\n await mkdir(projectDir, { recursive: true });\r\n dirSpinner.stop(`Created ${safeName}/`);\r\n\r\n // 9. Generate code\r\n const genSpinner = ora({ text: \"Generating architecture...\", color: \"cyan\" }).start();\r\n\r\n const result = await apiClient.generateCode({\r\n projectId,\r\n templateId,\r\n options: {\r\n includeValidations: true,\r\n includeComments: true,\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: true,\r\n includeReactions: true,\r\n includeOutbox: true,\r\n includeInbox: true,\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n genSpinner.succeed(chalk.green(`Generated ${result.files?.length || 0} files`));\r\n\r\n // 10. Write files to project directory\r\n const writeSpinner = p.spinner();\r\n writeSpinner.start(\"Writing files...\");\r\n\r\n // Organize files into backend folder\r\n const organizedFiles = result.files.map((file: { path: string; content: string; language: string }) => ({\r\n ...file,\r\n path: `backend/${file.path}`,\r\n }));\r\n\r\n await writeGeneratedFiles(organizedFiles, projectDir, false);\r\n writeSpinner.stop(`Wrote ${organizedFiles.length} files`);\r\n\r\n // 11. Create aerocoding.json\r\n const configSpinner = p.spinner();\r\n configSpinner.start(\"Creating config files...\");\r\n\r\n const projectConfig = createProjectConfig({\r\n projectId,\r\n templateId,\r\n templateVersion: \"1.0.0\", // TODO: get from template\r\n namespace: namespace as string,\r\n organizationId,\r\n output: { backend: \"./backend\", frontend: \"./frontend\" },\r\n });\r\n\r\n await saveProjectConfig(projectConfig, projectDir);\r\n\r\n // 12. Create aerocoding-manifest.json\r\n let manifest: AeroManifest = createEmptyManifest(\"1.0.0\");\r\n\r\n // Track all generated files in manifest\r\n for (const file of organizedFiles) {\r\n const hash = hashString(file.content);\r\n manifest = setManifestFile(manifest, file.path, {\r\n hash,\r\n mtime: Date.now(),\r\n size: Buffer.byteLength(file.content, \"utf-8\"),\r\n type: detectFileType(file.path),\r\n });\r\n }\r\n\r\n await writeManifest(projectDir, manifest);\r\n configSpinner.stop(\"Config files created\");\r\n\r\n // 13. Sync manifest to cloud\r\n try {\r\n const syncResult = await syncToCloud(apiClient, projectId, manifest);\r\n if (syncResult.success) {\r\n console.log(\r\n chalk.gray(\" ✓ Manifest synced to cloud\") +\r\n chalk.gray(` (${syncResult.fileCount} files)`)\r\n );\r\n }\r\n } catch {\r\n // Non-fatal - just log warning\r\n console.log(chalk.yellow(\" ⚠ Could not sync manifest to cloud\"));\r\n }\r\n\r\n // 14. Show results\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Project Created Successfully!\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n console.log(chalk.gray(\" Directory:\"), chalk.cyan(safeName + \"/\"));\r\n console.log(chalk.gray(\" Files:\"), chalk.cyan(organizedFiles.length));\r\n console.log(chalk.gray(\" Config:\"), chalk.cyan(PROJECT_CONFIG_FILENAME));\r\n console.log(chalk.gray(\" Manifest:\"), chalk.cyan(MANIFEST_FILENAME));\r\n\r\n if (result.creditsUsed !== undefined) {\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Credits used:\"), chalk.yellow(result.creditsUsed));\r\n console.log(chalk.gray(\" Credits remaining:\"), chalk.green(result.creditsRemaining));\r\n }\r\n\r\n p.outro(\r\n chalk.green(\"Project ready!\") +\r\n \"\\n\\n\" +\r\n chalk.gray(\" Next steps:\\n\") +\r\n chalk.cyan(` cd ${safeName}\\n`) +\r\n chalk.gray(\" # Make changes in the diagram editor\\n\") +\r\n chalk.cyan(\" aerocoding update\") +\r\n chalk.gray(\" # Sync changes incrementally\")\r\n );\r\n } catch (error: unknown) {\r\n const err = error as { response?: { status?: number; data?: { message?: string } }; message?: string };\r\n if (err.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n } else if (err.response?.data?.message) {\r\n p.cancel(err.response.data.message);\r\n } else {\r\n p.cancel(err.message || \"An unexpected error occurred\");\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * Convert string to PascalCase for .NET namespaces\r\n * \"mega-store\" → \"MegaStore\"\r\n * \"mega_store\" → \"MegaStore\"\r\n * \"mega store\" → \"MegaStore\"\r\n */\r\nfunction toPascalCase(str: string): string {\r\n return str\r\n .split(/[-_\\s]+/) // Split by hyphen, underscore, or space\r\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\r\n .join(\"\")\r\n .replace(/[^a-zA-Z0-9]/g, \"\"); // Remove any remaining special chars\r\n}\r\n\r\n/**\r\n * Detect file type from path for manifest categorization\r\n */\r\nfunction detectFileType(\r\n filePath: string\r\n): \"entity\" | \"usecase\" | \"repository\" | \"controller\" | \"dto\" | \"config\" | \"test\" | \"other\" {\r\n const lower = filePath.toLowerCase();\r\n\r\n if (lower.includes(\"/entities/\") || lower.includes(\"/domain/\")) return \"entity\";\r\n if (lower.includes(\"/usecases/\") || lower.includes(\"/application/\")) return \"usecase\";\r\n if (lower.includes(\"/repositories/\")) return \"repository\";\r\n if (lower.includes(\"/controllers/\") || lower.includes(\"/api/\")) return \"controller\";\r\n if (lower.includes(\"/dtos/\") || lower.includes(\"/dto/\")) return \"dto\";\r\n if (lower.includes(\".test.\") || lower.includes(\".spec.\") || lower.includes(\"/tests/\")) return \"test\";\r\n if (lower.includes(\"/config/\") || lower.includes(\"appsettings\") || lower.includes(\".csproj\")) return \"config\";\r\n\r\n return \"other\";\r\n}\r\n","import fs from \"fs/promises\";\r\nimport path from \"path\";\r\nimport chalk from \"chalk\";\r\nimport type { AeroManifest, ManifestFileEntry } from \"../manifest/index.js\";\r\nimport {\r\n createEmptyManifest,\r\n setManifestFile,\r\n writeManifest,\r\n readManifest,\r\n detectFileChange,\r\n hashString,\r\n} from \"../manifest/index.js\";\r\nimport {\r\n performMerge,\r\n writeConflictFiles,\r\n} from \"../merge/index.js\";\r\n\r\ninterface GeneratedFile {\r\n path: string;\r\n content: string;\r\n language: string;\r\n entityId?: string;\r\n /**\r\n * If true, file should only be written if it doesn't already exist.\r\n * Used for starter files (Program.cs, appsettings.json) that users may customize.\r\n */\r\n generateOnce?: boolean;\r\n /**\r\n * File type for manifest categorization\r\n */\r\n type?: ManifestFileEntry['type'];\r\n /**\r\n * Bounded context name for DDD organization\r\n */\r\n contextName?: string;\r\n}\r\n\r\n/**\r\n * Result of writing files with manifest tracking\r\n */\r\nexport interface WriteResult {\r\n created: string[];\r\n updated: string[];\r\n merged: string[];\r\n skipped: string[];\r\n conflicts: Array<{\r\n path: string;\r\n reason: string;\r\n newPath?: string;\r\n conflictPath?: string;\r\n }>;\r\n manifest: AeroManifest;\r\n}\r\n\r\nexport interface FileCategory {\r\n name: string;\r\n count: number;\r\n files: string[];\r\n}\r\n\r\n/**\r\n * Validate that a file path is safe and doesn't escape the output directory.\r\n * SECURITY: Prevents path traversal attacks (e.g., ../../../etc/passwd)\r\n */\r\nfunction isPathSafe(outputDir: string, filePath: string): boolean {\r\n // Resolve both paths to absolute paths\r\n const resolvedOutput = path.resolve(outputDir);\r\n const resolvedFile = path.resolve(outputDir, filePath);\r\n\r\n // Check if the resolved file path starts with the output directory\r\n // Also ensure there's a path separator after the base to prevent\r\n // matching \"output\" when file is in \"output-malicious\"\r\n return (\r\n resolvedFile.startsWith(resolvedOutput + path.sep) ||\r\n resolvedFile === resolvedOutput\r\n );\r\n}\r\n\r\n/**\r\n * Get category name from file path\r\n * Analyzes path segments to determine file type\r\n * @public Exported for use in preview/estimate display\r\n */\r\nexport function getCategoryFromPath(filePath: string): string {\r\n const lowerPath = filePath.toLowerCase();\r\n\r\n // Order matters - more specific first\r\n if (lowerPath.includes(\"/controllers/\")) return \"Controllers\";\r\n if (lowerPath.includes(\"/usecases/\") || lowerPath.includes(\"/use-cases/\"))\r\n return \"UseCases\";\r\n if (lowerPath.includes(\"/dtos/\") || lowerPath.includes(\"/dto/\")) return \"DTOs\";\r\n if (lowerPath.includes(\"/entities/\")) return \"Entities\";\r\n if (\r\n lowerPath.includes(\"/repositories/\") ||\r\n lowerPath.includes(\"/repositoriesimpl/\")\r\n )\r\n return \"Repositories\";\r\n if (\r\n lowerPath.includes(\"/configurations/\") ||\r\n lowerPath.includes(\"/config/\")\r\n )\r\n return \"Configurations\";\r\n if (\r\n lowerPath.includes(\"/validators/\") ||\r\n lowerPath.includes(\"/validation/\")\r\n )\r\n return \"Validators\";\r\n if (lowerPath.includes(\"/mappers/\")) return \"Mappers\";\r\n if (lowerPath.includes(\"/interfaces/\")) return \"Interfaces\";\r\n if (lowerPath.includes(\"/exceptions/\")) return \"Exceptions\";\r\n if (lowerPath.includes(\"/vos/\") || lowerPath.includes(\"/valueobjects/\"))\r\n return \"ValueObjects\";\r\n if (lowerPath.includes(\"/ioc/\") || lowerPath.includes(\"/di/\"))\r\n return \"DependencyInjection\";\r\n if (\r\n lowerPath.includes(\"/tests/\") ||\r\n lowerPath.includes(\".test.\") ||\r\n lowerPath.includes(\".spec.\")\r\n )\r\n return \"Tests\";\r\n if (lowerPath.includes(\"/database/\")) return \"Database\";\r\n\r\n return \"Other\";\r\n}\r\n\r\n/**\r\n * Categorize file paths into categories\r\n * Used for preview/estimate display before generation\r\n * @public Exported for use in generate command preview\r\n */\r\nexport function categorizeFilePaths(filePaths: string[]): FileCategory[] {\r\n const categories = new Map<string, string[]>();\r\n\r\n for (const filePath of filePaths) {\r\n const category = getCategoryFromPath(filePath);\r\n const existing = categories.get(category) || [];\r\n existing.push(filePath);\r\n categories.set(category, existing);\r\n }\r\n\r\n return Array.from(categories.entries())\r\n .map(([name, fileList]) => ({ name, count: fileList.length, files: fileList }))\r\n .sort((a, b) => b.count - a.count); // Most files first\r\n}\r\n\r\n/**\r\n * Categorize files by their path\r\n * Groups files into categories like Entities, DTOs, UseCases, etc.\r\n */\r\nfunction categorizeFiles(files: GeneratedFile[]): FileCategory[] {\r\n return categorizeFilePaths(files.map((f) => f.path));\r\n}\r\n\r\n/**\r\n * Display categorized summary of generated files\r\n */\r\nfunction displayCategorizedSummary(files: GeneratedFile[]): void {\r\n const categories = categorizeFiles(files);\r\n\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Generated Files\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n // Find max name length for alignment\r\n const maxNameLength = Math.max(...categories.map((c) => c.name.length));\r\n\r\n for (const category of categories) {\r\n const padding = \" \".repeat(maxNameLength - category.name.length + 2);\r\n const countStr = category.count.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.gray(` ${category.name}${padding}`),\r\n chalk.cyan(`${countStr} files`)\r\n );\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n const totalPadding = \" \".repeat(maxNameLength - 5 + 2);\r\n const totalStr = files.length.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.white(` Total${totalPadding}`),\r\n chalk.bold.cyan(`${totalStr} files`)\r\n );\r\n}\r\n\r\n/**\r\n * Write generated files to disk\r\n *\r\n * Creates directories as needed and writes files\r\n * Shows categorized summary by default, or full list with verbose=true\r\n */\r\nexport async function writeGeneratedFiles(\r\n files: GeneratedFile[],\r\n outputDir: string,\r\n verbose: boolean = false\r\n): Promise<void> {\r\n // Track written files for summary\r\n const writtenFiles: GeneratedFile[] = [];\r\n\r\n // Track skipped generateOnce files for summary\r\n const skippedOnceFiles: string[] = [];\r\n\r\n for (const file of files) {\r\n // SECURITY: Validate path doesn't escape output directory\r\n if (!isPathSafe(outputDir, file.path)) {\r\n console.error(chalk.red(` Skipping unsafe path: ${file.path}`));\r\n console.error(\r\n chalk.gray(\r\n ` Path traversal detected - file path must be within output directory`\r\n )\r\n );\r\n continue;\r\n }\r\n\r\n const fullPath = path.resolve(outputDir, file.path);\r\n const dir = path.dirname(fullPath);\r\n\r\n // Check if file has generateOnce flag and already exists\r\n if (file.generateOnce) {\r\n try {\r\n await fs.access(fullPath);\r\n // File exists - skip it\r\n skippedOnceFiles.push(file.path);\r\n continue;\r\n } catch {\r\n // File doesn't exist - proceed with generation\r\n }\r\n }\r\n\r\n try {\r\n // Create directory if doesn't exist\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Write file\r\n await fs.writeFile(fullPath, file.content, \"utf-8\");\r\n\r\n // Show file path in verbose mode\r\n if (verbose) {\r\n console.log(chalk.gray(` ${file.path}`));\r\n }\r\n\r\n writtenFiles.push(file);\r\n } catch (error: any) {\r\n console.error(chalk.red(` Failed to write ${file.path}`));\r\n console.error(chalk.gray(` ${error.message}`));\r\n }\r\n }\r\n\r\n // Show categorized summary (unless verbose)\r\n if (!verbose && writtenFiles.length > 0) {\r\n displayCategorizedSummary(writtenFiles);\r\n }\r\n\r\n // Show skipped generateOnce files\r\n if (skippedOnceFiles.length > 0) {\r\n console.log(\"\");\r\n console.log(\r\n chalk.gray(` Skipped ${skippedOnceFiles.length} existing file(s) (generateOnce):`)\r\n );\r\n for (const filePath of skippedOnceFiles) {\r\n console.log(chalk.gray(` - ${filePath}`));\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Infer file type from path for manifest categorization\r\n */\r\nfunction inferFileType(filePath: string): ManifestFileEntry['type'] {\r\n const lowerPath = filePath.toLowerCase();\r\n\r\n if (lowerPath.includes('/entities/')) return 'entity';\r\n if (lowerPath.includes('/usecases/') || lowerPath.includes('/use-cases/')) return 'usecase';\r\n if (lowerPath.includes('/repositories/')) return 'repository';\r\n if (lowerPath.includes('/controllers/')) return 'controller';\r\n if (lowerPath.includes('/dtos/') || lowerPath.includes('/dto/')) return 'dto';\r\n if (lowerPath.includes('/tests/') || lowerPath.includes('.test.') || lowerPath.includes('.spec.')) return 'test';\r\n if (lowerPath.includes('/config') || lowerPath.includes('appsettings')) return 'config';\r\n\r\n return 'other';\r\n}\r\n\r\n/**\r\n * Write generated files to disk with manifest tracking\r\n *\r\n * This is the incremental-aware version that:\r\n * 1. Checks if files have been modified by user (via manifest)\r\n * 2. Only overwrites unmodified files\r\n * 3. Flags conflicts for user-modified files\r\n * 4. Updates manifest with new file hashes\r\n */\r\nexport async function writeGeneratedFilesWithManifest(\r\n files: GeneratedFile[],\r\n outputDir: string,\r\n templateVersion: string,\r\n options: {\r\n verbose?: boolean;\r\n forceOverwrite?: boolean;\r\n } = {}\r\n): Promise<WriteResult> {\r\n const { verbose = false, forceOverwrite = false } = options;\r\n\r\n // Load existing manifest or create new one\r\n let manifest = await readManifest(outputDir) || createEmptyManifest(templateVersion);\r\n\r\n const result: WriteResult = {\r\n created: [],\r\n updated: [],\r\n merged: [],\r\n skipped: [],\r\n conflicts: [],\r\n manifest,\r\n };\r\n\r\n for (const file of files) {\r\n // SECURITY: Validate path doesn't escape output directory\r\n if (!isPathSafe(outputDir, file.path)) {\r\n console.error(chalk.red(` Skipping unsafe path: ${file.path}`));\r\n continue;\r\n }\r\n\r\n const fullPath = path.resolve(outputDir, file.path);\r\n const dir = path.dirname(fullPath);\r\n const manifestEntry = manifest.files[file.path];\r\n\r\n // Detect if file has changed\r\n const changeStatus = await detectFileChange(fullPath, manifestEntry);\r\n\r\n let shouldWrite = false;\r\n let action: 'create' | 'update' | 'skip' | 'conflict' = 'skip';\r\n\r\n switch (changeStatus.status) {\r\n case 'new':\r\n // File doesn't exist - create it\r\n shouldWrite = true;\r\n action = 'create';\r\n break;\r\n\r\n case 'unchanged':\r\n // File exists but wasn't modified by user - safe to overwrite\r\n shouldWrite = true;\r\n action = 'update';\r\n break;\r\n\r\n case 'modified':\r\n // File was modified by user - try three-way merge\r\n if (forceOverwrite) {\r\n shouldWrite = true;\r\n action = 'update';\r\n } else {\r\n // Perform three-way merge\r\n const currentContent = await fs.readFile(fullPath, 'utf-8');\r\n\r\n // Get base content from what we last generated (stored hash matches original)\r\n // We need to regenerate base from the hash... but we only have the hash.\r\n // For now, use the generated content as base if this is an update scenario.\r\n // In a proper implementation, we'd store the original content or retrieve it.\r\n //\r\n // Since we don't have the original base content stored, we'll use a simplified approach:\r\n // - If the generated content is the same as before (hash matches), skip\r\n // - Otherwise, try merge with empty base (essentially a diff)\r\n\r\n // For Phase 2, we use the manifest hash to detect changes but can't do true 3-way merge\r\n // without storing base content. For now, generate conflict files.\r\n const mergeResult = performMerge(\r\n manifestEntry?.hash ? '' : '', // We don't have base content stored\r\n currentContent,\r\n file.content\r\n );\r\n\r\n if (mergeResult.success) {\r\n // Merge succeeded - write merged content\r\n shouldWrite = true;\r\n action = 'update';\r\n // Override file.content with merged result\r\n (file as any)._mergedContent = mergeResult.content;\r\n result.merged.push(file.path);\r\n } else {\r\n // Merge has conflicts - write .new and .conflict files\r\n action = 'conflict';\r\n\r\n // Create directory if needed\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Write conflict files\r\n const { newPath, conflictPath } = await writeConflictFiles(\r\n fullPath,\r\n file.content,\r\n mergeResult.conflicts,\r\n currentContent\r\n );\r\n\r\n result.conflicts.push({\r\n path: file.path,\r\n reason: 'Merge conflict - manual resolution required',\r\n newPath: path.relative(outputDir, newPath),\r\n conflictPath: path.relative(outputDir, conflictPath),\r\n });\r\n }\r\n }\r\n break;\r\n\r\n case 'deleted':\r\n // File was in manifest but deleted by user - skip it\r\n action = 'skip';\r\n result.skipped.push(file.path);\r\n break;\r\n\r\n case 'unknown':\r\n // File exists but not in manifest (user created it outside AeroCoding)\r\n action = 'skip';\r\n result.skipped.push(file.path);\r\n break;\r\n }\r\n\r\n // Handle generateOnce files\r\n if (file.generateOnce && changeStatus.status !== 'new') {\r\n shouldWrite = false;\r\n action = 'skip';\r\n if (!result.skipped.includes(file.path)) {\r\n result.skipped.push(file.path);\r\n }\r\n }\r\n\r\n if (shouldWrite) {\r\n try {\r\n // Create directory if doesn't exist\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Use merged content if available, otherwise original\r\n const contentToWrite = (file as any)._mergedContent || file.content;\r\n\r\n // Write file\r\n await fs.writeFile(fullPath, contentToWrite, \"utf-8\");\r\n\r\n // Get file stats for manifest\r\n const stats = await fs.stat(fullPath);\r\n\r\n // Update manifest entry\r\n const entry: ManifestFileEntry = {\r\n hash: hashString(contentToWrite),\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n entityId: file.entityId,\r\n type: file.type || inferFileType(file.path),\r\n contextName: file.contextName,\r\n };\r\n\r\n manifest = setManifestFile(manifest, file.path, entry);\r\n\r\n // Track result based on action\r\n const isMerged = result.merged.includes(file.path);\r\n if (action === 'create') {\r\n result.created.push(file.path);\r\n if (verbose) {\r\n console.log(chalk.green(` ✓ Created ${file.path}`));\r\n }\r\n } else if (isMerged) {\r\n // Already added to merged array\r\n if (verbose) {\r\n console.log(chalk.magenta(` ✓ Merged ${file.path}`));\r\n }\r\n } else {\r\n result.updated.push(file.path);\r\n if (verbose) {\r\n console.log(chalk.blue(` ✓ Updated ${file.path}`));\r\n }\r\n }\r\n } catch (error: any) {\r\n console.error(chalk.red(` Failed to write ${file.path}`));\r\n console.error(chalk.gray(` ${error.message}`));\r\n }\r\n } else if (action === 'conflict' && verbose) {\r\n console.log(chalk.yellow(` ⚠ Conflict ${file.path}`));\r\n }\r\n }\r\n\r\n // Update manifest timestamp and save\r\n manifest = {\r\n ...manifest,\r\n lastSync: new Date().toISOString(),\r\n templateVersion,\r\n };\r\n\r\n await writeManifest(outputDir, manifest);\r\n result.manifest = manifest;\r\n\r\n // Show summary\r\n if (!verbose) {\r\n displayIncrementalSummary(result);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Display summary of incremental write operation\r\n */\r\nfunction displayIncrementalSummary(result: WriteResult): void {\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Update Results\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (result.created.length > 0) {\r\n console.log(chalk.green(` ✓ Created: ${result.created.length} files`));\r\n }\r\n if (result.updated.length > 0) {\r\n console.log(chalk.blue(` ✓ Updated: ${result.updated.length} files`));\r\n }\r\n if (result.merged.length > 0) {\r\n console.log(chalk.magenta(` ✓ Merged: ${result.merged.length} files`));\r\n }\r\n if (result.skipped.length > 0) {\r\n console.log(chalk.gray(` ○ Skipped: ${result.skipped.length} files`));\r\n }\r\n if (result.conflicts.length > 0) {\r\n console.log(chalk.yellow(` ⚠ Conflicts: ${result.conflicts.length} files`));\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n const total = result.created.length + result.updated.length + result.merged.length;\r\n console.log(chalk.white(` Total written: ${total} files`));\r\n\r\n // Show conflict details with file paths\r\n if (result.conflicts.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.yellow(\" ⚠ Conflicts need manual resolution:\"));\r\n console.log(\"\");\r\n\r\n for (const conflict of result.conflicts.slice(0, 5)) {\r\n console.log(chalk.yellow(` ${conflict.path}`));\r\n if (conflict.newPath) {\r\n console.log(chalk.gray(` → ${conflict.newPath}`));\r\n }\r\n if (conflict.conflictPath) {\r\n console.log(chalk.gray(` → ${conflict.conflictPath}`));\r\n }\r\n }\r\n\r\n if (result.conflicts.length > 5) {\r\n console.log(chalk.gray(` ... and ${result.conflicts.length - 5} more`));\r\n }\r\n\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Run 'aerocoding resolve' after fixing conflicts.\"));\r\n }\r\n}\r\n","// ============================================\r\n// Manifest Module\r\n// Public code for tracking generated files\r\n// ============================================\r\n\r\nimport * as fs from 'fs/promises';\r\nimport * as path from 'path';\r\nimport type { AeroManifest, ManifestFileEntry } from './types.js';\r\nimport { MANIFEST_VERSION, MANIFEST_FILENAME } from './types.js';\r\n\r\n// Re-export types\r\nexport type { AeroManifest, ManifestFileEntry, FileChangeStatus } from './types.js';\r\nexport { MANIFEST_VERSION, MANIFEST_FILENAME } from './types.js';\r\n\r\n// Re-export hash utilities\r\nexport { hashString, hashFile, detectFileChange } from './hash-utils.js';\r\n\r\n/**\r\n * Read manifest from a directory\r\n */\r\nexport async function readManifest(projectDir: string): Promise<AeroManifest | null> {\r\n const manifestPath = path.join(projectDir, MANIFEST_FILENAME);\r\n\r\n try {\r\n const content = await fs.readFile(manifestPath, 'utf-8');\r\n return JSON.parse(content) as AeroManifest;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n return null;\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Write manifest to a directory\r\n */\r\nexport async function writeManifest(projectDir: string, manifest: AeroManifest): Promise<void> {\r\n const manifestPath = path.join(projectDir, MANIFEST_FILENAME);\r\n await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\r\n}\r\n\r\n/**\r\n * Create a new empty manifest\r\n */\r\nexport function createEmptyManifest(templateVersion: string): AeroManifest {\r\n return {\r\n version: MANIFEST_VERSION,\r\n lastSync: new Date().toISOString(),\r\n templateVersion,\r\n files: {},\r\n entities: [],\r\n };\r\n}\r\n\r\n/**\r\n * Add or update a file entry in the manifest\r\n */\r\nexport function setManifestFile(\r\n manifest: AeroManifest,\r\n filePath: string,\r\n entry: ManifestFileEntry\r\n): AeroManifest {\r\n return {\r\n ...manifest,\r\n files: {\r\n ...manifest.files,\r\n [filePath]: entry,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Check if manifest exists in a directory\r\n */\r\nexport async function hasManifest(projectDir: string): Promise<boolean> {\r\n const manifest = await readManifest(projectDir);\r\n return manifest !== null;\r\n}\r\n","// ============================================\r\n// Manifest Types for Incremental Generation\r\n// Public code - safe to distribute with CLI\r\n// ============================================\r\n\r\n/**\r\n * aerocoding-manifest.json entry for a single file\r\n */\r\nexport interface ManifestFileEntry {\r\n /** SHA-256 hash of file content */\r\n hash: string;\r\n /** File modification time in milliseconds */\r\n mtime: number;\r\n /** File size in bytes */\r\n size: number;\r\n /** Related entity ID (if applicable) */\r\n entityId?: string;\r\n /** File type for categorization */\r\n type?: 'entity' | 'usecase' | 'repository' | 'controller' | 'dto' | 'config' | 'test' | 'other';\r\n /** Bounded context name */\r\n contextName?: string;\r\n}\r\n\r\n/**\r\n * aerocoding-manifest.json structure\r\n * Tracks all generated files and their hashes\r\n */\r\nexport interface AeroManifest {\r\n /** Manifest format version */\r\n version: string;\r\n /** Last sync timestamp */\r\n lastSync: string;\r\n /** Template version at last generation */\r\n templateVersion: string;\r\n /** Map of file paths to their metadata */\r\n files: Record<string, ManifestFileEntry>;\r\n /** Entities that were generated */\r\n entities?: Array<{\r\n id: string;\r\n name: string;\r\n hash: string;\r\n contextName?: string;\r\n }>;\r\n}\r\n\r\n/**\r\n * Result of comparing a file with its manifest entry\r\n */\r\nexport type FileChangeStatus =\r\n | { status: 'new' }\r\n | { status: 'unchanged' }\r\n | { status: 'modified'; currentHash: string }\r\n | { status: 'deleted' }\r\n | { status: 'unknown' };\r\n\r\n// Constants\r\nexport const MANIFEST_VERSION = '1.0.0';\r\nexport const MANIFEST_FILENAME = 'aerocoding-manifest.json';\r\n","// ============================================\r\n// Hash Utilities for Incremental Generation\r\n// Public code - safe to distribute with CLI\r\n// ============================================\r\n\r\nimport * as crypto from 'crypto';\r\nimport * as fs from 'fs/promises';\r\nimport { createReadStream } from 'fs';\r\nimport type { ManifestFileEntry, FileChangeStatus } from './types.js';\r\n\r\n/**\r\n * Compute SHA-256 hash of a string\r\n */\r\nexport function hashString(content: string): string {\r\n return crypto.createHash('sha256').update(content, 'utf-8').digest('hex');\r\n}\r\n\r\n/**\r\n * Compute SHA-256 hash of a file using streaming (memory efficient)\r\n */\r\nexport async function hashFile(filePath: string): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const hash = crypto.createHash('sha256');\r\n const stream = createReadStream(filePath);\r\n\r\n stream.on('data', (chunk) => hash.update(chunk));\r\n stream.on('end', () => resolve(hash.digest('hex')));\r\n stream.on('error', reject);\r\n });\r\n}\r\n\r\n/**\r\n * Get file stats (mtime and size) for quick comparison\r\n */\r\nexport async function getFileStats(filePath: string): Promise<{ mtime: number; size: number } | null> {\r\n try {\r\n const stats = await fs.stat(filePath);\r\n return {\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Quick check if file might have changed based on mtime and size\r\n * Returns true if file MIGHT have changed (need hash verification)\r\n */\r\nexport function mightHaveChanged(\r\n currentStats: { mtime: number; size: number },\r\n manifestEntry: ManifestFileEntry\r\n): boolean {\r\n return currentStats.mtime !== manifestEntry.mtime || currentStats.size !== manifestEntry.size;\r\n}\r\n\r\n/**\r\n * Detect if a file has been modified by the user\r\n * Uses optimized two-phase check: mtime/size first, then hash if needed\r\n */\r\nexport async function detectFileChange(\r\n filePath: string,\r\n manifestEntry: ManifestFileEntry | undefined\r\n): Promise<FileChangeStatus> {\r\n const stats = await getFileStats(filePath);\r\n\r\n if (!stats) {\r\n if (manifestEntry) {\r\n return { status: 'deleted' };\r\n }\r\n return { status: 'new' };\r\n }\r\n\r\n if (!manifestEntry) {\r\n return { status: 'unknown' };\r\n }\r\n\r\n // Quick check with mtime/size\r\n if (!mightHaveChanged(stats, manifestEntry)) {\r\n return { status: 'unchanged' };\r\n }\r\n\r\n // Verify with hash\r\n const currentHash = await hashFile(filePath);\r\n\r\n if (currentHash === manifestEntry.hash) {\r\n return { status: 'unchanged' };\r\n }\r\n\r\n return { status: 'modified', currentHash };\r\n}\r\n","// ============================================\r\n// Three-Way Merge Implementation\r\n// ============================================\r\n\r\nimport diff3Merge from \"diff3\";\r\n\r\n/**\r\n * Result of a three-way merge operation\r\n */\r\nexport interface MergeResult {\r\n /** Whether the merge completed without conflicts */\r\n success: boolean;\r\n /** The merged content (may contain conflict markers if success=false) */\r\n content: string;\r\n /** Conflict regions if merge had conflicts */\r\n conflicts: ConflictRegion[];\r\n}\r\n\r\n/**\r\n * A region of conflict between user's changes and generated changes\r\n */\r\nexport interface ConflictRegion {\r\n /** Starting line number in the merged output */\r\n startLine: number;\r\n /** Ending line number in the merged output */\r\n endLine: number;\r\n /** User's version of the conflicting section */\r\n yours: string;\r\n /** Generated version of the conflicting section */\r\n generated: string;\r\n}\r\n\r\n/**\r\n * Perform a three-way merge between base, current (user's), and generated content.\r\n *\r\n * @param base - The original content (what was last generated/synced)\r\n * @param current - The current content on disk (may have user modifications)\r\n * @param generated - The newly generated content from the API\r\n * @returns MergeResult with success status, merged content, and any conflicts\r\n *\r\n * @example\r\n * ```typescript\r\n * const result = performMerge(\r\n * \"class Customer { }\", // base\r\n * \"class Customer { IsVip() }\", // current (user added method)\r\n * \"class Customer { Phone; }\" // generated (API added property)\r\n * );\r\n *\r\n * if (result.success) {\r\n * // Merged: class Customer { IsVip(); Phone; }\r\n * await writeFile(path, result.content);\r\n * } else {\r\n * // Has conflicts, need manual resolution\r\n * await writeConflictFiles(path, current, generated, result.conflicts);\r\n * }\r\n * ```\r\n */\r\nexport function performMerge(\r\n base: string,\r\n current: string,\r\n generated: string\r\n): MergeResult {\r\n // Split content into lines for diff3\r\n const baseLines = base.split(\"\\n\");\r\n const currentLines = current.split(\"\\n\");\r\n const generatedLines = generated.split(\"\\n\");\r\n\r\n // Perform three-way merge\r\n // diff3 returns array of regions: either string[] (clean) or { ok: string[] } or { conflict: { a, o, b } }\r\n const merged = diff3Merge(currentLines, baseLines, generatedLines);\r\n\r\n const conflicts: ConflictRegion[] = [];\r\n const outputLines: string[] = [];\r\n let lineNumber = 1;\r\n\r\n for (const region of merged) {\r\n if (Array.isArray(region)) {\r\n // Clean region - lines that merged without conflict\r\n outputLines.push(...region);\r\n lineNumber += region.length;\r\n } else if (\"ok\" in region && region.ok) {\r\n // OK region - also clean\r\n const okLines = region.ok;\r\n outputLines.push(...okLines);\r\n lineNumber += okLines.length;\r\n } else if (\"conflict\" in region && region.conflict) {\r\n // Conflict region\r\n const conflictData = region.conflict;\r\n const yoursLines = conflictData.a || [];\r\n const generatedLines = conflictData.b || [];\r\n const yours = yoursLines.join(\"\\n\");\r\n const generatedStr = generatedLines.join(\"\\n\");\r\n\r\n // Add conflict markers to output\r\n const conflictLines = [\r\n \"<<<<<<< YOURS\",\r\n ...yoursLines,\r\n \"=======\",\r\n ...generatedLines,\r\n \">>>>>>> GENERATED\",\r\n ];\r\n\r\n const startLine = lineNumber;\r\n outputLines.push(...conflictLines);\r\n lineNumber += conflictLines.length;\r\n\r\n conflicts.push({\r\n startLine,\r\n endLine: lineNumber - 1,\r\n yours,\r\n generated: generatedStr,\r\n });\r\n }\r\n }\r\n\r\n return {\r\n success: conflicts.length === 0,\r\n content: outputLines.join(\"\\n\"),\r\n conflicts,\r\n };\r\n}\r\n\r\n/**\r\n * Check if content has any conflict markers\r\n */\r\nexport function hasConflictMarkers(content: string): boolean {\r\n return (\r\n content.includes(\"<<<<<<< YOURS\") ||\r\n content.includes(\"=======\") ||\r\n content.includes(\">>>>>>> GENERATED\")\r\n );\r\n}\r\n\r\n/**\r\n * Extract clean content by removing conflict markers (for preview purposes)\r\n * Takes the \"YOURS\" side of each conflict\r\n */\r\nexport function extractYoursSide(content: string): string {\r\n const lines = content.split(\"\\n\");\r\n const output: string[] = [];\r\n let inConflict = false;\r\n let inGenerated = false;\r\n\r\n for (const line of lines) {\r\n if (line === \"<<<<<<< YOURS\") {\r\n inConflict = true;\r\n inGenerated = false;\r\n continue;\r\n }\r\n if (line === \"=======\") {\r\n inGenerated = true;\r\n continue;\r\n }\r\n if (line === \">>>>>>> GENERATED\") {\r\n inConflict = false;\r\n inGenerated = false;\r\n continue;\r\n }\r\n\r\n if (!inConflict || !inGenerated) {\r\n output.push(line);\r\n }\r\n }\r\n\r\n return output.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Extract clean content by removing conflict markers\r\n * Takes the \"GENERATED\" side of each conflict\r\n */\r\nexport function extractGeneratedSide(content: string): string {\r\n const lines = content.split(\"\\n\");\r\n const output: string[] = [];\r\n let inConflict = false;\r\n let inYours = false;\r\n\r\n for (const line of lines) {\r\n if (line === \"<<<<<<< YOURS\") {\r\n inConflict = true;\r\n inYours = true;\r\n continue;\r\n }\r\n if (line === \"=======\") {\r\n inYours = false;\r\n continue;\r\n }\r\n if (line === \">>>>>>> GENERATED\") {\r\n inConflict = false;\r\n continue;\r\n }\r\n\r\n if (!inConflict || !inYours) {\r\n output.push(line);\r\n }\r\n }\r\n\r\n return output.join(\"\\n\");\r\n}\r\n","// ============================================\r\n// Conflict File Writer\r\n// ============================================\r\n\r\nimport { writeFile, unlink, access } from \"node:fs/promises\";\r\nimport { basename, extname } from \"node:path\";\r\nimport type { ConflictRegion } from \"./merger.js\";\r\n\r\n/**\r\n * Extensions for conflict files\r\n */\r\nexport const CONFLICT_NEW_EXT = \".new\";\r\nexport const CONFLICT_DIFF_EXT = \".conflict\";\r\n\r\n/**\r\n * Write conflict files when merge fails\r\n *\r\n * Creates two files:\r\n * - `file.ext.new` - The newly generated version (complete)\r\n * - `file.ext.conflict` - A diff showing the conflicts with context\r\n *\r\n * The original file is left untouched.\r\n *\r\n * @param filePath - Path to the original file\r\n * @param generatedContent - The newly generated content\r\n * @param conflicts - The conflict regions from merge\r\n * @param currentContent - The current user content (for context in .conflict)\r\n */\r\nexport async function writeConflictFiles(\r\n filePath: string,\r\n generatedContent: string,\r\n conflicts: ConflictRegion[],\r\n currentContent: string\r\n): Promise<{ newPath: string; conflictPath: string }> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n // Write .new file with complete generated content\r\n await writeFile(newPath, generatedContent, \"utf-8\");\r\n\r\n // Write .conflict file with diff format\r\n const conflictContent = generateConflictFile(\r\n filePath,\r\n currentContent,\r\n generatedContent,\r\n conflicts\r\n );\r\n await writeFile(conflictPath, conflictContent, \"utf-8\");\r\n\r\n return { newPath, conflictPath };\r\n}\r\n\r\n/**\r\n * Generate the content of a .conflict file\r\n */\r\nfunction generateConflictFile(\r\n filePath: string,\r\n _currentContent: string,\r\n _generatedContent: string,\r\n conflicts: ConflictRegion[]\r\n): string {\r\n const fileName = basename(filePath);\r\n const ext = extname(filePath);\r\n const commentStyle = getCommentStyle(ext);\r\n\r\n const header = `${commentStyle.start}\r\n${commentStyle.prefix} ${fileName} - MERGE CONFLICT\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} This file has ${conflicts.length} conflict(s) that need manual resolution.\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} Resolution options:\r\n${commentStyle.prefix} 1. Edit ${fileName} to include both your changes and the generated changes\r\n${commentStyle.prefix} 2. Copy desired parts from ${fileName}${CONFLICT_NEW_EXT}\r\n${commentStyle.prefix} 3. Run 'aerocoding resolve' when done\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} Your file: ${fileName} (unchanged)\r\n${commentStyle.prefix} Generated: ${fileName}${CONFLICT_NEW_EXT} (new version)\r\n${commentStyle.end}\r\n\r\n`;\r\n\r\n const conflictSections = conflicts\r\n .map((conflict, index) => {\r\n return `${commentStyle.start}\r\n${commentStyle.prefix} CONFLICT ${index + 1} of ${conflicts.length} (lines ${conflict.startLine}-${conflict.endLine})\r\n${commentStyle.end}\r\n\r\n<<<<<<< YOURS (keep your changes)\r\n${conflict.yours}\r\n=======\r\n${conflict.generated}\r\n>>>>>>> GENERATED (from template)\r\n`;\r\n })\r\n .join(\"\\n\");\r\n\r\n return header + conflictSections;\r\n}\r\n\r\n/**\r\n * Get comment style based on file extension\r\n */\r\nfunction getCommentStyle(ext: string): {\r\n start: string;\r\n prefix: string;\r\n end: string;\r\n} {\r\n switch (ext.toLowerCase()) {\r\n case \".cs\":\r\n case \".ts\":\r\n case \".tsx\":\r\n case \".js\":\r\n case \".jsx\":\r\n case \".java\":\r\n case \".kt\":\r\n case \".dart\":\r\n case \".go\":\r\n case \".swift\":\r\n case \".rs\":\r\n case \".c\":\r\n case \".cpp\":\r\n case \".h\":\r\n return { start: \"/*\", prefix: \" *\", end: \" */\" };\r\n\r\n case \".py\":\r\n case \".rb\":\r\n case \".sh\":\r\n case \".yaml\":\r\n case \".yml\":\r\n return { start: \"#\", prefix: \"#\", end: \"#\" };\r\n\r\n case \".html\":\r\n case \".xml\":\r\n case \".xaml\":\r\n case \".svg\":\r\n return { start: \"<!--\", prefix: \" \", end: \"-->\" };\r\n\r\n case \".sql\":\r\n return { start: \"--\", prefix: \"--\", end: \"--\" };\r\n\r\n case \".css\":\r\n case \".scss\":\r\n case \".less\":\r\n return { start: \"/*\", prefix: \" *\", end: \" */\" };\r\n\r\n default:\r\n return { start: \"//\", prefix: \"//\", end: \"//\" };\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file has pending conflict files\r\n */\r\nexport async function hasConflictFiles(filePath: string): Promise<boolean> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n try {\r\n await access(newPath);\r\n return true;\r\n } catch {\r\n // .new doesn't exist\r\n }\r\n\r\n try {\r\n await access(conflictPath);\r\n return true;\r\n } catch {\r\n // .conflict doesn't exist\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Remove conflict files after resolution\r\n */\r\nexport async function removeConflictFiles(\r\n filePath: string\r\n): Promise<{ removedNew: boolean; removedConflict: boolean }> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n let removedNew = false;\r\n let removedConflict = false;\r\n\r\n try {\r\n await unlink(newPath);\r\n removedNew = true;\r\n } catch {\r\n // File didn't exist, that's fine\r\n }\r\n\r\n try {\r\n await unlink(conflictPath);\r\n removedConflict = true;\r\n } catch {\r\n // File didn't exist, that's fine\r\n }\r\n\r\n return { removedNew, removedConflict };\r\n}\r\n\r\n/**\r\n * Find all conflict files in a directory\r\n */\r\nexport function getConflictFilePaths(originalPath: string): {\r\n newPath: string;\r\n conflictPath: string;\r\n} {\r\n return {\r\n newPath: `${originalPath}${CONFLICT_NEW_EXT}`,\r\n conflictPath: `${originalPath}${CONFLICT_DIFF_EXT}`,\r\n };\r\n}\r\n","import { z } from \"zod\";\r\nimport { readFile, writeFile, access } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\n\r\n// ============================================\r\n// aerocoding.json - Project Configuration\r\n// New format for incremental generation\r\n// ============================================\r\n\r\nexport const PROJECT_CONFIG_FILENAME = \"aerocoding.json\";\r\n\r\n/**\r\n * Schema for aerocoding.json\r\n * This is the user-editable config for the meta-framework approach\r\n */\r\nexport const projectConfigSchema = z.object({\r\n $schema: z.string().optional().default(\"https://aerocoding.dev/schema.json\"),\r\n\r\n /** Project UUID from aerocoding.dev */\r\n projectId: z.string().uuid(),\r\n\r\n /** Template ID for architecture generation */\r\n templateId: z.string().min(1),\r\n\r\n /** Template version at project creation */\r\n templateVersion: z.string().optional(),\r\n\r\n /** Root namespace/package name */\r\n namespace: z.string().min(1),\r\n\r\n /** Output directories */\r\n output: z.object({\r\n backend: z.string().default(\"./backend\"),\r\n frontend: z.string().default(\"./frontend\"),\r\n }).optional().default({ backend: \"./backend\", frontend: \"./frontend\" }),\r\n\r\n /** Organization ID (for cloud sync) */\r\n organizationId: z.string().uuid().optional(),\r\n});\r\n\r\nexport type ProjectConfig = z.infer<typeof projectConfigSchema>;\r\n\r\n/**\r\n * Check if aerocoding.json exists in a directory\r\n */\r\nexport async function projectConfigExists(dir: string = process.cwd()): Promise<boolean> {\r\n try {\r\n await access(join(dir, PROJECT_CONFIG_FILENAME));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Load aerocoding.json from a directory\r\n */\r\nexport async function loadProjectConfig(dir: string = process.cwd()): Promise<ProjectConfig | null> {\r\n try {\r\n const configPath = join(dir, PROJECT_CONFIG_FILENAME);\r\n const content = await readFile(configPath, \"utf-8\");\r\n const parsed = JSON.parse(content);\r\n return projectConfigSchema.parse(parsed);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Save aerocoding.json to a directory\r\n */\r\nexport async function saveProjectConfig(config: ProjectConfig, dir: string = process.cwd()): Promise<void> {\r\n const configPath = join(dir, PROJECT_CONFIG_FILENAME);\r\n const content = JSON.stringify(config, null, 2);\r\n await writeFile(configPath, content, \"utf-8\");\r\n}\r\n\r\n/**\r\n * Create a new project config\r\n */\r\nexport function createProjectConfig(options: {\r\n projectId: string;\r\n templateId: string;\r\n templateVersion?: string;\r\n namespace: string;\r\n organizationId?: string;\r\n output?: { backend?: string; frontend?: string };\r\n}): ProjectConfig {\r\n return {\r\n $schema: \"https://aerocoding.dev/schema.json\",\r\n projectId: options.projectId,\r\n templateId: options.templateId,\r\n templateVersion: options.templateVersion,\r\n namespace: options.namespace,\r\n organizationId: options.organizationId,\r\n output: {\r\n backend: options.output?.backend || \"./backend\",\r\n frontend: options.output?.frontend || \"./frontend\",\r\n },\r\n };\r\n}\r\n","// ============================================\r\n// Cloud Sync - Manifest Backup/Recovery\r\n// ============================================\r\n\r\nimport { ApiClient, CloudManifest } from \"../api/client.js\";\r\nimport type { AeroManifest } from \"../manifest/types.js\";\r\n\r\n/**\r\n * Convert local manifest to cloud format\r\n * Strips entities array (not needed for cloud backup)\r\n */\r\nexport function toCloudManifest(manifest: AeroManifest): CloudManifest {\r\n return {\r\n version: manifest.version,\r\n lastSync: manifest.lastSync,\r\n templateVersion: manifest.templateVersion,\r\n files: manifest.files,\r\n };\r\n}\r\n\r\n/**\r\n * Convert cloud manifest back to local format\r\n */\r\nexport function fromCloudManifest(\r\n cloudManifest: CloudManifest,\r\n templateVersion: string\r\n): AeroManifest {\r\n return {\r\n version: cloudManifest.version,\r\n lastSync: cloudManifest.lastSync || new Date().toISOString(),\r\n templateVersion: cloudManifest.templateVersion || templateVersion,\r\n files: cloudManifest.files,\r\n entities: [], // Will be rebuilt on next generation\r\n };\r\n}\r\n\r\n/**\r\n * Sync local manifest to cloud\r\n *\r\n * @returns Success status and file count\r\n */\r\nexport async function syncToCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n manifest: AeroManifest\r\n): Promise<{ success: boolean; fileCount: number }> {\r\n const cloudManifest = toCloudManifest(manifest);\r\n const result = await apiClient.saveManifest(projectId, cloudManifest);\r\n\r\n return {\r\n success: result.success,\r\n fileCount: result.fileCount,\r\n };\r\n}\r\n\r\n/**\r\n * Fetch manifest from cloud\r\n *\r\n * @returns Manifest or null if not found\r\n */\r\nexport async function fetchFromCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n templateVersion: string\r\n): Promise<AeroManifest | null> {\r\n const cloudManifest = await apiClient.getManifest(projectId);\r\n\r\n if (!cloudManifest) {\r\n return null;\r\n }\r\n\r\n return fromCloudManifest(cloudManifest, templateVersion);\r\n}\r\n\r\n/**\r\n * Check if cloud has a more recent manifest\r\n *\r\n * @returns Object with comparison info\r\n */\r\nexport async function compareWithCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n localManifest: AeroManifest | null\r\n): Promise<{\r\n hasCloudBackup: boolean;\r\n cloudLastSync: string | null;\r\n localLastSync: string | null;\r\n isCloudNewer: boolean;\r\n cloudFileCount: number;\r\n localFileCount: number;\r\n}> {\r\n const cloudManifest = await apiClient.getManifest(projectId);\r\n\r\n const cloudLastSync = cloudManifest?.lastSync || null;\r\n const localLastSync = localManifest?.lastSync || null;\r\n const cloudFileCount = cloudManifest ? Object.keys(cloudManifest.files).length : 0;\r\n const localFileCount = localManifest ? Object.keys(localManifest.files).length : 0;\r\n\r\n // Determine if cloud is newer\r\n let isCloudNewer = false;\r\n if (cloudLastSync && localLastSync) {\r\n isCloudNewer = new Date(cloudLastSync) > new Date(localLastSync);\r\n } else if (cloudLastSync && !localLastSync) {\r\n isCloudNewer = true;\r\n }\r\n\r\n return {\r\n hasCloudBackup: cloudManifest !== null,\r\n cloudLastSync,\r\n localLastSync,\r\n isCloudNewer,\r\n cloudFileCount,\r\n localFileCount,\r\n };\r\n}\r\n\r\n/**\r\n * Format a date for display\r\n */\r\nexport function formatSyncDate(isoDate: string | null): string {\r\n if (!isoDate) return \"never\";\r\n\r\n const date = new Date(isoDate);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return \"just now\";\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n\r\n return date.toLocaleDateString();\r\n}\r\n","// ============================================\r\n// Update Command - Incremental Code Generation\r\n// ============================================\r\n\r\nimport * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\nimport { writeGeneratedFilesWithManifest } from \"../utils/file-writer.js\";\r\nimport { loadProjectConfig, PROJECT_CONFIG_FILENAME } from \"../config/project-config.js\";\r\nimport { readManifest, writeManifest } from \"../manifest/index.js\";\r\nimport {\r\n syncToCloud,\r\n fetchFromCloud,\r\n compareWithCloud,\r\n formatSyncDate,\r\n} from \"../utils/cloud-sync.js\";\r\n\r\ninterface UpdateOptions {\r\n force?: boolean;\r\n verbose?: boolean;\r\n dryRun?: boolean;\r\n}\r\n\r\n/**\r\n * Update Command\r\n *\r\n * Incrementally updates generated code by:\r\n * 1. Reading aerocoding.json config\r\n * 2. Fetching latest schema from aerocoding.dev\r\n * 3. Regenerating code with current template\r\n * 4. Using three-way merge to preserve user changes\r\n * 5. Creating .new/.conflict files for manual resolution\r\n *\r\n * @ai-critical Core command for incremental generation workflow\r\n */\r\nexport async function updateCommand(options: UpdateOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Update \"));\r\n\r\n // 1. Load project config\r\n const config = await loadProjectConfig();\r\n\r\n if (!config) {\r\n p.cancel(\r\n `No ${PROJECT_CONFIG_FILENAME} found. Run 'aerocoding create' first.`\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // 2. Check authentication\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n p.cancel(\"Not logged in. Run 'aerocoding login' first.\");\r\n process.exit(1);\r\n }\r\n\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n\r\n try {\r\n // 3. Load existing manifest (if any)\r\n let manifest = await readManifest(process.cwd());\r\n let fileCount = manifest ? Object.keys(manifest.files).length : 0;\r\n\r\n if (manifest) {\r\n p.log.info(\r\n `Found manifest with ${fileCount} tracked files (last sync: ${manifest.lastSync || \"unknown\"})`\r\n );\r\n } else {\r\n // No local manifest - check cloud for backup\r\n p.log.warn(\"No local manifest found.\");\r\n\r\n const cloudCheck = await compareWithCloud(apiClient, config.projectId, null);\r\n\r\n if (cloudCheck.hasCloudBackup) {\r\n p.log.info(\r\n chalk.cyan(\r\n ` Cloud backup available (${cloudCheck.cloudFileCount} files, synced ${formatSyncDate(cloudCheck.cloudLastSync)})`\r\n )\r\n );\r\n\r\n const recovery = await p.select({\r\n message: \"How would you like to proceed?\",\r\n options: [\r\n {\r\n value: \"restore\",\r\n label: \"Restore from cloud backup\",\r\n hint: \"recommended\",\r\n },\r\n {\r\n value: \"continue\",\r\n label: \"Continue anyway\",\r\n hint: \"all files will be treated as new\",\r\n },\r\n { value: \"cancel\", label: \"Cancel\" },\r\n ],\r\n });\r\n\r\n if (p.isCancel(recovery) || recovery === \"cancel\") {\r\n p.cancel(\"Update cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n if (recovery === \"restore\") {\r\n const restoreSpinner = p.spinner();\r\n restoreSpinner.start(\"Restoring manifest from cloud...\");\r\n\r\n const cloudManifest = await fetchFromCloud(\r\n apiClient,\r\n config.projectId,\r\n config.templateVersion || \"1.0.0\"\r\n );\r\n\r\n if (cloudManifest) {\r\n await writeManifest(process.cwd(), cloudManifest);\r\n manifest = cloudManifest;\r\n fileCount = Object.keys(manifest.files).length;\r\n restoreSpinner.stop(\r\n chalk.green(`Restored ${fileCount} files from cloud backup`)\r\n );\r\n } else {\r\n restoreSpinner.stop(chalk.yellow(\"Cloud backup not found\"));\r\n }\r\n }\r\n } else {\r\n p.log.info(\r\n chalk.gray(\" No cloud backup available. All generated files will be created as new.\")\r\n );\r\n }\r\n }\r\n\r\n // 4. Fetch project details\r\n const projectSpinner = p.spinner();\r\n projectSpinner.start(\"Fetching project details...\");\r\n const project = await apiClient.getProject(config.projectId);\r\n projectSpinner.stop(`Project: ${project.name}`);\r\n\r\n // 5. Show update summary\r\n p.log.step(chalk.bold(\"Update Configuration:\"));\r\n p.log.info(` Project: ${project.name}`);\r\n p.log.info(` Template: ${config.templateId}`);\r\n p.log.info(` Namespace: ${config.namespace}`);\r\n p.log.info(` Output: ${config.output.backend}`);\r\n\r\n if (options.dryRun) {\r\n p.log.info(chalk.yellow(\" Mode: DRY RUN (no files will be written)\"));\r\n }\r\n if (options.force) {\r\n p.log.info(chalk.yellow(\" Mode: FORCE (will overwrite modified files)\"));\r\n }\r\n\r\n // 6. Get credit estimate BEFORE confirmation\r\n let estimatedCredits = 0;\r\n let creditsRemaining = 0;\r\n\r\n const estimateSpinner = p.spinner();\r\n estimateSpinner.start(\"Calculating credit cost...\");\r\n\r\n try {\r\n const estimate = await apiClient.estimateCreditCost({\r\n projectId: config.projectId,\r\n templateId: config.templateId,\r\n options: {\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: false,\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n estimatedCredits = estimate.estimatedCredits;\r\n\r\n // Get remaining credits\r\n const creditUsage = await apiClient.getCreditUsage(project.organizationId);\r\n creditsRemaining = creditUsage.remaining;\r\n\r\n estimateSpinner.stop(\"Credit estimate calculated\");\r\n } catch {\r\n estimateSpinner.stop(\"Could not estimate credits (will be calculated on generation)\");\r\n }\r\n\r\n if (estimatedCredits > 0) {\r\n console.log(\"\");\r\n p.log.info(chalk.yellow(` Estimated Credits: ~${estimatedCredits}`));\r\n p.log.info(chalk.gray(` Your Balance: ${creditsRemaining}`));\r\n\r\n if (creditsRemaining < estimatedCredits) {\r\n p.log.warn(chalk.red(\" ⚠ You may not have enough credits for this generation.\"));\r\n }\r\n }\r\n\r\n // 7. Confirm update\r\n if (!options.dryRun) {\r\n const proceed = await p.confirm({\r\n message: estimatedCredits > 0\r\n ? `Proceed with update (~${estimatedCredits} credits)?`\r\n : \"Proceed with update?\",\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Update cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n\r\n // 7. Generate code\r\n const genSpinner = ora({\r\n text: \"Generating code from latest schema...\",\r\n color: \"cyan\",\r\n }).start();\r\n\r\n const result = await apiClient.generateCode({\r\n projectId: config.projectId,\r\n templateId: config.templateId,\r\n options: {\r\n includeValidations: true,\r\n includeComments: true,\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: false, // Don't regenerate starter files\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n genSpinner.succeed(\r\n chalk.green(`Generated ${result.files?.length || 0} files from schema`)\r\n );\r\n\r\n if (options.dryRun) {\r\n // Dry run - just show what would happen\r\n p.log.info(\"\");\r\n p.log.info(chalk.bold(\" Dry Run Results:\"));\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n p.log.info(` Files to process: ${result.files?.length || 0}`);\r\n p.log.info(` Tracked files: ${fileCount}`);\r\n p.log.info(\"\");\r\n p.log.info(chalk.gray(\" Run without --dry-run to apply changes.\"));\r\n\r\n p.outro(chalk.green(\"Dry run complete!\"));\r\n return;\r\n }\r\n\r\n // 8. Apply updates with merge\r\n const updateSpinner = p.spinner();\r\n updateSpinner.start(\"Applying updates...\");\r\n\r\n // Organize files into backend folder (matching create command structure)\r\n const organizedFiles = result.files.map(\r\n (file: { path: string; content: string; language: string }) => ({\r\n ...file,\r\n path: `${config.output.backend.replace(/^\\.\\//, \"\")}/${file.path}`,\r\n })\r\n );\r\n\r\n const writeResult = await writeGeneratedFilesWithManifest(\r\n organizedFiles,\r\n process.cwd(),\r\n config.templateVersion || \"1.0.0\",\r\n {\r\n verbose: options.verbose,\r\n forceOverwrite: options.force,\r\n }\r\n );\r\n\r\n updateSpinner.stop(\"Update complete\");\r\n\r\n // 9. Show credits\r\n if (result.creditsUsed !== undefined) {\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Credits used:\"), chalk.yellow(result.creditsUsed));\r\n console.log(\r\n chalk.gray(\" Credits remaining:\"),\r\n chalk.green(result.creditsRemaining)\r\n );\r\n }\r\n\r\n // 10. Sync manifest to cloud\r\n try {\r\n const syncResult = await syncToCloud(\r\n apiClient,\r\n config.projectId,\r\n writeResult.manifest\r\n );\r\n if (syncResult.success) {\r\n console.log(\r\n chalk.gray(\" ✓ Manifest synced to cloud\") +\r\n chalk.gray(` (${syncResult.fileCount} files)`)\r\n );\r\n }\r\n } catch (syncError) {\r\n // Non-fatal - just log warning\r\n console.log(chalk.yellow(\" ⚠ Could not sync manifest to cloud\"));\r\n if (options.verbose) {\r\n console.log(chalk.gray(` ${(syncError as Error).message}`));\r\n }\r\n }\r\n\r\n // 11. Show final message\r\n if (writeResult.conflicts.length > 0) {\r\n p.outro(\r\n chalk.yellow(`Update complete with ${writeResult.conflicts.length} conflict(s).`) +\r\n \"\\n\" +\r\n chalk.gray(\" Run 'aerocoding resolve' after fixing conflicts.\")\r\n );\r\n } else {\r\n const totalWritten =\r\n writeResult.created.length +\r\n writeResult.updated.length +\r\n writeResult.merged.length;\r\n\r\n p.outro(\r\n chalk.green(`Update complete! ${totalWritten} file(s) written.`)\r\n );\r\n }\r\n } catch (error: unknown) {\r\n const err = error as {\r\n response?: { status?: number; data?: { message?: string } };\r\n message?: string;\r\n };\r\n if (err.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n } else if (err.response?.data?.message) {\r\n p.cancel(err.response.data.message);\r\n } else {\r\n p.cancel(err.message || \"An unexpected error occurred\");\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n","// ============================================\r\n// Resolve Command - Clean up merge conflicts\r\n// ============================================\r\n\r\nimport * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport { readdir, stat } from \"node:fs/promises\";\r\nimport { join, relative } from \"node:path\";\r\nimport {\r\n removeConflictFiles,\r\n CONFLICT_NEW_EXT,\r\n CONFLICT_DIFF_EXT,\r\n} from \"../merge/index.js\";\r\nimport {\r\n readManifest,\r\n writeManifest,\r\n setManifestFile,\r\n hashFile,\r\n} from \"../manifest/index.js\";\r\nimport { loadProjectConfig, PROJECT_CONFIG_FILENAME } from \"../config/project-config.js\";\r\n\r\ninterface ResolveOptions {\r\n verbose?: boolean;\r\n all?: boolean;\r\n}\r\n\r\ninterface ConflictFile {\r\n originalPath: string;\r\n newPath: string;\r\n conflictPath: string;\r\n}\r\n\r\n/**\r\n * Resolve Command\r\n *\r\n * Cleans up conflict files after user has manually resolved merge conflicts.\r\n *\r\n * Flow:\r\n * 1. Find all .new and .conflict files\r\n * 2. For each conflict:\r\n * - Verify original file exists (user resolved it)\r\n * - Remove .new and .conflict files\r\n * - Update manifest with new hash\r\n *\r\n * @ai-critical Part of incremental generation workflow\r\n */\r\nexport async function resolveCommand(options: ResolveOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Resolve \"));\r\n\r\n // 1. Load project config\r\n const config = await loadProjectConfig();\r\n\r\n if (!config) {\r\n p.cancel(\r\n `No ${PROJECT_CONFIG_FILENAME} found. Run 'aerocoding create' first.`\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // 2. Find all conflict files\r\n const spinner = p.spinner();\r\n spinner.start(\"Scanning for conflict files...\");\r\n\r\n const conflicts = await findConflictFiles(process.cwd());\r\n spinner.stop(`Found ${conflicts.length} conflict(s)`);\r\n\r\n if (conflicts.length === 0) {\r\n p.log.success(\"No conflicts to resolve!\");\r\n p.outro(chalk.green(\"All clear!\"));\r\n return;\r\n }\r\n\r\n // 3. Show conflicts\r\n p.log.info(\"\");\r\n p.log.info(chalk.bold(\" Pending Conflicts:\"));\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n for (const conflict of conflicts) {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n p.log.info(chalk.yellow(` ⚠ ${relPath}`));\r\n if (options.verbose) {\r\n p.log.info(chalk.gray(` → ${relative(process.cwd(), conflict.newPath)}`));\r\n p.log.info(\r\n chalk.gray(` → ${relative(process.cwd(), conflict.conflictPath)}`)\r\n );\r\n }\r\n }\r\n\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n p.log.info(\"\");\r\n\r\n // 4. Confirm resolution\r\n if (!options.all) {\r\n const proceed = await p.confirm({\r\n message: `Remove ${conflicts.length} conflict file(s)? (This assumes you've resolved them)`,\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Resolution cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n\r\n // 5. Load manifest\r\n let manifest = await readManifest(process.cwd());\r\n\r\n if (!manifest) {\r\n p.cancel(\"No manifest found. Cannot update file hashes.\");\r\n process.exit(1);\r\n }\r\n\r\n // 6. Resolve each conflict\r\n const resolveSpinner = p.spinner();\r\n resolveSpinner.start(\"Resolving conflicts...\");\r\n\r\n let resolved = 0;\r\n let failed = 0;\r\n\r\n for (const conflict of conflicts) {\r\n try {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n\r\n // Verify original file exists\r\n try {\r\n await stat(conflict.originalPath);\r\n } catch {\r\n if (options.verbose) {\r\n console.log(\r\n chalk.red(` ✗ ${relPath} - original file not found`)\r\n );\r\n }\r\n failed++;\r\n continue;\r\n }\r\n\r\n // Remove conflict files\r\n const { removedNew, removedConflict } = await removeConflictFiles(\r\n conflict.originalPath\r\n );\r\n\r\n // Update manifest with new hash\r\n const newHash = await hashFile(conflict.originalPath);\r\n const stats = await stat(conflict.originalPath);\r\n\r\n // Get path relative to project root for manifest\r\n const manifestPath = relPath.replace(/\\\\/g, \"/\");\r\n const existingEntry = manifest.files[manifestPath];\r\n\r\n manifest = setManifestFile(manifest, manifestPath, {\r\n hash: newHash,\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n entityId: existingEntry?.entityId,\r\n type: existingEntry?.type || \"other\",\r\n contextName: existingEntry?.contextName,\r\n });\r\n\r\n if (options.verbose) {\r\n const removed = [];\r\n if (removedNew) removed.push(\".new\");\r\n if (removedConflict) removed.push(\".conflict\");\r\n console.log(\r\n chalk.green(` ✓ ${relPath}`) +\r\n chalk.gray(` (removed ${removed.join(\", \")})`)\r\n );\r\n }\r\n\r\n resolved++;\r\n } catch (error) {\r\n failed++;\r\n if (options.verbose) {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n console.log(chalk.red(` ✗ ${relPath} - ${error}`));\r\n }\r\n }\r\n }\r\n\r\n // 7. Save updated manifest\r\n manifest = {\r\n ...manifest,\r\n lastSync: new Date().toISOString(),\r\n };\r\n\r\n await writeManifest(process.cwd(), manifest);\r\n resolveSpinner.stop(\"Conflicts resolved\");\r\n\r\n // 8. Show results\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Resolution Results\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (resolved > 0) {\r\n console.log(chalk.green(` ✓ Resolved: ${resolved} files`));\r\n }\r\n if (failed > 0) {\r\n console.log(chalk.red(` ✗ Failed: ${failed} files`));\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (failed > 0) {\r\n p.outro(\r\n chalk.yellow(\r\n `Resolved ${resolved} conflict(s), ${failed} failed.`\r\n )\r\n );\r\n } else {\r\n p.outro(chalk.green(`All ${resolved} conflict(s) resolved!`));\r\n }\r\n}\r\n\r\n/**\r\n * Recursively find all conflict files in a directory\r\n */\r\nasync function findConflictFiles(dir: string): Promise<ConflictFile[]> {\r\n const conflicts: ConflictFile[] = [];\r\n\r\n async function scan(currentDir: string) {\r\n try {\r\n const entries = await readdir(currentDir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = join(currentDir, entry.name);\r\n\r\n // Skip node_modules and hidden directories\r\n if (entry.isDirectory()) {\r\n if (\r\n entry.name === \"node_modules\" ||\r\n entry.name === \".git\" ||\r\n entry.name.startsWith(\".\")\r\n ) {\r\n continue;\r\n }\r\n await scan(fullPath);\r\n } else if (entry.isFile()) {\r\n // Check for .new files\r\n if (entry.name.endsWith(CONFLICT_NEW_EXT)) {\r\n const originalPath = fullPath.slice(\r\n 0,\r\n -CONFLICT_NEW_EXT.length\r\n );\r\n const conflictPath = originalPath + CONFLICT_DIFF_EXT;\r\n\r\n // Only add if we haven't already found this conflict\r\n const existing = conflicts.find(\r\n (c) => c.originalPath === originalPath\r\n );\r\n if (!existing) {\r\n conflicts.push({\r\n originalPath,\r\n newPath: fullPath,\r\n conflictPath,\r\n });\r\n }\r\n }\r\n // Check for .conflict files (in case .new was deleted)\r\n else if (entry.name.endsWith(CONFLICT_DIFF_EXT)) {\r\n const originalPath = fullPath.slice(\r\n 0,\r\n -CONFLICT_DIFF_EXT.length\r\n );\r\n const newPath = originalPath + CONFLICT_NEW_EXT;\r\n\r\n // Only add if we haven't already found this conflict\r\n const existing = conflicts.find(\r\n (c) => c.originalPath === originalPath\r\n );\r\n if (!existing) {\r\n conflicts.push({\r\n originalPath,\r\n newPath,\r\n conflictPath: fullPath,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n } catch {\r\n // Ignore directories we can't read\r\n }\r\n }\r\n\r\n await scan(dir);\r\n return conflicts;\r\n}\r\n"],"mappings":"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","names":["chalk","spinner","resolve","axios","API_URL","chalk","chalk","chalk","chalk","chalk","chalk","chalk","ora","access","fs","path","chalk","fs","resolve","generatedLines","writeFile","path","chalk","fs","readFile","writeFile","access","join","join","readFile","writeFile","chalk","spinner","access","ora","p","chalk","ora","chalk","ora","p","chalk","stat","join","chalk","spinner","stat","join"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/auth/device-flow.ts","../src/auth/token-manager.ts","../src/api/client.ts","../src/commands/_shared/create-api-client.ts","../src/commands/_shared/unauthorized.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/create.ts","../src/utils/file-writer.ts","../src/manifest/index.ts","../src/manifest/types.ts","../src/manifest/hash-utils.ts","../src/merge/merger.ts","../src/merge/conflict-writer.ts","../src/config/project-config.ts","../src/utils/cloud-sync.ts","../src/commands/update.ts","../src/commands/resolve.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Command } from \"commander\";\r\nimport { loginCommand } from \"./commands/login.js\";\r\nimport { logoutCommand } from \"./commands/logout.js\";\r\nimport { whoamiCommand } from \"./commands/whoami.js\";\r\nimport { createCommand } from \"./commands/create.js\";\r\nimport { updateCommand } from \"./commands/update.js\";\r\nimport { resolveCommand } from \"./commands/resolve.js\";\r\nimport \"dotenv/config\";\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name(\"aerocoding\")\r\n .description(\"AeroCoding CLI - Generate production-ready code from UML diagrams\")\r\n .version(\"0.1.28\");\r\n\r\n// ============================================\r\n// Authentication Commands\r\n// ============================================\r\n\r\nprogram\r\n .command(\"login\")\r\n .description(\"Authenticate with AeroCoding\")\r\n .action(loginCommand);\r\n\r\nprogram\r\n .command(\"logout\")\r\n .description(\"Logout and clear stored credentials\")\r\n .action(logoutCommand);\r\n\r\nprogram\r\n .command(\"whoami\")\r\n .description(\"Show current authenticated user\")\r\n .action(whoamiCommand);\r\n\r\n// ============================================\r\n// Project Commands\r\n// ============================================\r\n\r\nprogram\r\n .command(\"create [name]\")\r\n .description(\"Create a new AeroCoding project with full architecture\")\r\n .option(\"-t, --template <id>\", \"Template ID (skip selection)\")\r\n .option(\"-p, --project <id>\", \"Project ID (skip selection)\")\r\n .option(\"-f, --force\", \"Overwrite existing directory without asking\")\r\n .action(createCommand);\r\n\r\nprogram\r\n .command(\"update\")\r\n .description(\"Update generated code incrementally (preserves your changes)\")\r\n .option(\"-f, --force\", \"Overwrite modified files without merging\")\r\n .option(\"-v, --verbose\", \"Show detailed file operations\")\r\n .option(\"--dry-run\", \"Preview changes without writing files\")\r\n .action(updateCommand);\r\n\r\nprogram\r\n .command(\"resolve\")\r\n .description(\"Clean up conflict files after manual resolution\")\r\n .option(\"-v, --verbose\", \"Show detailed resolution info\")\r\n .option(\"-a, --all\", \"Resolve all conflicts without confirmation\")\r\n .action(resolveCommand);\r\n\r\n// ============================================\r\n// Parse and Execute\r\n// ============================================\r\n\r\nprogram.parse();\r\n","import chalk from \"chalk\";\r\nimport { DeviceFlow } from \"../auth/device-flow.js\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\n\r\n/**\r\n * Login Command\r\n *\r\n * Authenticates user via OAuth Device Flow\r\n * Stores tokens securely in OS credential manager\r\n */\r\nexport async function loginCommand() {\r\n console.log(chalk.bold(\"\\nAeroCoding CLI Login\\n\"));\r\n\r\n const tokenManager = new TokenManager();\r\n\r\n // Check if already logged in\r\n const existingToken = await tokenManager.getAccessToken();\r\n if (existingToken) {\r\n const metadata = await tokenManager.getUserMetadata();\r\n console.log(\r\n chalk.yellow(\"Already logged in as:\"),\r\n chalk.white(metadata?.email || \"unknown\")\r\n );\r\n console.log(\r\n chalk.gray(\r\n \" Run 'aerocoding logout' to login with a different account\\n\"\r\n )\r\n );\r\n return;\r\n }\r\n\r\n try {\r\n // Initiate device flow\r\n const deviceFlow = new DeviceFlow();\r\n const tokens = await deviceFlow.initiateAuth();\r\n\r\n // Get user info\r\n const apiClient = createApiClientWithAutoLogout(\r\n tokens.access_token,\r\n tokenManager\r\n );\r\n let user;\r\n try {\r\n user = await apiClient.getCurrentUser();\r\n } catch (error: any) {\r\n if (error.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n }\r\n throw error;\r\n }\r\n\r\n // Save tokens\r\n await tokenManager.saveTokens(tokens.access_token, tokens.refresh_token, {\r\n id: user.id,\r\n email: user.email,\r\n name: user.name || undefined,\r\n tier: user.tier,\r\n });\r\n\r\n console.log(\"\");\r\n console.log(\r\n chalk.green(\"Successfully logged in as:\"),\r\n chalk.white(user.email)\r\n );\r\n console.log(chalk.gray(\" Run 'aerocoding whoami' to verify\\n\"));\r\n } catch (error: any) {\r\n console.error(\r\n chalk.red(\"\\nLogin failed:\"),\r\n error.message || \"Unknown error\"\r\n );\r\n process.exit(1);\r\n }\r\n}\r\n","import axios from \"axios\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport open from \"open\";\r\n\r\nconst API_URL = process.env.API_URL || \"https://aerocoding.dev\";\r\nconst MAX_POLL_TIME = 15 * 60 * 1000; // 15 minutes\r\n\r\ninterface DeviceAuthResponse {\r\n device_code: string;\r\n user_code: string;\r\n confirmation_code: string;\r\n verification_uri: string;\r\n verification_uri_complete: string;\r\n expires_in: number;\r\n interval: number;\r\n}\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token: string;\r\n token_type: string;\r\n expires_in: number;\r\n}\r\n\r\n/**\r\n * DeviceFlow\r\n *\r\n * Implements OAuth 2.0 Device Authorization Grant (RFC 8628)\r\n * Used for CLI authentication without browser-based redirects\r\n */\r\nexport class DeviceFlow {\r\n /**\r\n * Initiate the complete device authorization flow\r\n */\r\n async initiateAuth(): Promise<TokenResponse> {\r\n // Step 1: Request device code\r\n const deviceAuth = await this.requestDeviceCode();\r\n\r\n // Step 2: Display user code and open browser\r\n this.displayUserCode(deviceAuth);\r\n await this.openBrowser(deviceAuth.verification_uri);\r\n\r\n // Step 3: Poll for authorization\r\n const tokens = await this.pollForToken(deviceAuth);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Step 1: Request device code from server\r\n */\r\n private async requestDeviceCode(): Promise<DeviceAuthResponse> {\r\n try {\r\n const response = await axios.post(`${API_URL}/api/device/authorize`, {\r\n client_id: \"aerocoding-cli\",\r\n scope: \"generate:code projects:read\",\r\n });\r\n\r\n return response.data;\r\n } catch (error: any) {\r\n console.error(chalk.red(\"Failed to initiate device authorization\"));\r\n if (error.response) {\r\n console.error(\r\n chalk.red(`Error: ${error.response.data.error_description}`)\r\n );\r\n }\r\n throw new Error(\"Failed to initiate device authorization\");\r\n }\r\n }\r\n\r\n /**\r\n * Step 2: Display user code and instructions\r\n */\r\n private displayUserCode(auth: DeviceAuthResponse): void {\r\n console.log(\"\\n\");\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(chalk.bold.white(\" AeroCoding CLI - Device Activation\"));\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(\"\");\r\n console.log(chalk.white(\" 1. Open this URL in your browser:\"));\r\n console.log(chalk.cyan.bold(` ${auth.verification_uri}`));\r\n console.log(\"\");\r\n console.log(chalk.white(\" 2. Enter this code:\"));\r\n console.log(chalk.green.bold(` ${auth.user_code}`));\r\n console.log(\"\");\r\n console.log(\r\n chalk.gray(` Code expires in ${auth.expires_in / 60} minutes`)\r\n );\r\n console.log(chalk.cyan(\"━\".repeat(60)));\r\n console.log(\"\");\r\n }\r\n\r\n /**\r\n * Step 2.5: Open browser automatically\r\n */\r\n private async openBrowser(url: string): Promise<void> {\r\n try {\r\n await open(url);\r\n console.log(chalk.gray(\" Opening browser...\"));\r\n } catch {\r\n console.log(chalk.yellow(\" Could not open browser automatically\"));\r\n console.log(chalk.gray(\" Please open the URL manually\\n\"));\r\n }\r\n }\r\n\r\n /**\r\n * Step 3: Poll for token\r\n */\r\n private async pollForToken(auth: DeviceAuthResponse): Promise<TokenResponse> {\r\n const spinner = ora({\r\n text: \"Waiting for authorization...\",\r\n color: \"cyan\",\r\n }).start();\r\n\r\n const startTime = Date.now();\r\n let currentInterval = auth.interval * 1000;\r\n\r\n while (true) {\r\n // Check timeout\r\n if (Date.now() - startTime > MAX_POLL_TIME) {\r\n spinner.fail(chalk.red(\"Authorization timeout\"));\r\n throw new Error(\"Device authorization timed out\");\r\n }\r\n\r\n try {\r\n const response = await axios.post(`${API_URL}/api/device/token`, {\r\n device_code: auth.device_code,\r\n client_id: \"aerocoding-cli\",\r\n });\r\n\r\n spinner.succeed(chalk.green(\"Successfully authenticated!\"));\r\n return response.data;\r\n } catch (error: any) {\r\n const errorCode = error.response?.data?.error;\r\n const errorDescription = error.response?.data?.error_description;\r\n\r\n if (errorCode === \"authorization_pending\") {\r\n // Keep polling\r\n await this.sleep(currentInterval);\r\n continue;\r\n }\r\n\r\n if (errorCode === \"slow_down\") {\r\n // Increase poll interval by 5 seconds\r\n currentInterval += 5000;\r\n spinner.text = \"Polling... (slowed down to avoid spam)\";\r\n await this.sleep(currentInterval);\r\n continue;\r\n }\r\n\r\n if (errorCode === \"expired_token\") {\r\n spinner.fail(chalk.red(\"Authorization code expired\"));\r\n throw new Error(\"Device code expired. Please try again.\");\r\n }\r\n\r\n if (errorCode === \"access_denied\") {\r\n spinner.fail(chalk.red(\"Authorization denied\"));\r\n throw new Error(\"You denied the authorization request\");\r\n }\r\n\r\n // Unknown error\r\n spinner.fail(chalk.red(\"Authorization failed\"));\r\n console.error(\r\n chalk.red(`Error: ${errorDescription || \"Unknown error\"}`)\r\n );\r\n throw new Error(errorDescription || \"Unknown error\");\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Helper: Sleep for specified milliseconds\r\n */\r\n private sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n}\r\n","import { Entry } from \"@napi-rs/keyring\";\r\nimport { createClient, SupabaseClient } from \"@supabase/supabase-js\";\r\n\r\nconst SERVICE_NAME = \"aerocoding-cli\";\r\n\r\n// Public Supabase credentials (anon key is safe to expose)\r\nconst SUPABASE_URL = \"https://peqpttkvdpjgmduzacwl.supabase.co\";\r\nconst SUPABASE_ANON_KEY = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBlcXB0dGt2ZHBqZ21kdXphY3dsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjQyNjUxNzMsImV4cCI6MjA3OTg0MTE3M30.WAzqgZusGoOEHxidfHc1e4daBglG4DJG5LOXbqldWQA\";\r\n\r\ninterface UserMetadata {\r\n id: string;\r\n email: string;\r\n name?: string;\r\n tier?: string;\r\n}\r\n\r\n/**\r\n * Helper functions for keyring operations using Entry class\r\n */\r\nfunction getPassword(service: string, account: string): string | null {\r\n try {\r\n const entry = new Entry(service, account);\r\n return entry.getPassword();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction setPassword(service: string, account: string, password: string): void {\r\n const entry = new Entry(service, account);\r\n entry.setPassword(password);\r\n}\r\n\r\nfunction deletePassword(service: string, account: string): void {\r\n try {\r\n const entry = new Entry(service, account);\r\n entry.deletePassword();\r\n } catch {\r\n // Ignore if entry doesn't exist\r\n }\r\n}\r\n\r\n/**\r\n * TokenManager\r\n *\r\n * Manages secure storage and automatic refresh of authentication tokens\r\n * Uses OS-level credential managers (Keychain/Credential Manager/Secret Service)\r\n */\r\nexport class TokenManager {\r\n private supabase: SupabaseClient;\r\n\r\n constructor() {\r\n this.supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {\r\n auth: {\r\n autoRefreshToken: false,\r\n persistSession: false,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get access token, automatically refreshing if expired\r\n */\r\n async getAccessToken(): Promise<string | null> {\r\n try {\r\n let accessToken = getPassword(SERVICE_NAME, \"access_token\");\r\n\r\n if (!accessToken) {\r\n return null;\r\n }\r\n\r\n // Check if expired\r\n if (this.isTokenExpired(accessToken)) {\r\n accessToken = await this.refreshTokens();\r\n }\r\n\r\n return accessToken;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Refresh tokens using stored refresh token\r\n */\r\n private async refreshTokens(): Promise<string | null> {\r\n try {\r\n const refreshToken = getPassword(SERVICE_NAME, \"refresh_token\");\r\n\r\n if (!refreshToken) {\r\n throw new Error(\"No refresh token available\");\r\n }\r\n\r\n const { data, error } = await this.supabase.auth.refreshSession({\r\n refresh_token: refreshToken,\r\n });\r\n\r\n if (error || !data.session) {\r\n throw new Error(\"Failed to refresh session\");\r\n }\r\n\r\n // Store new tokens (single-use refresh token rotation)\r\n setPassword(SERVICE_NAME, \"access_token\", data.session.access_token);\r\n setPassword(SERVICE_NAME, \"refresh_token\", data.session.refresh_token);\r\n\r\n return data.session.access_token;\r\n } catch {\r\n await this.logout();\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Check if JWT token is expired (or expires in < 5 min)\r\n */\r\n private isTokenExpired(token: string): boolean {\r\n try {\r\n const payload = JSON.parse(\r\n Buffer.from(token.split(\".\")[1]!, \"base64\").toString()\r\n );\r\n const expiresAt = payload.exp * 1000;\r\n const now = Date.now();\r\n\r\n // Refresh 5 minutes before expiration\r\n return expiresAt - now < 5 * 60 * 1000;\r\n } catch {\r\n return true; // Treat invalid tokens as expired\r\n }\r\n }\r\n\r\n /**\r\n * Save tokens and user metadata after successful login\r\n */\r\n async saveTokens(\r\n accessToken: string,\r\n refreshToken: string,\r\n user: UserMetadata\r\n ): Promise<void> {\r\n setPassword(SERVICE_NAME, \"access_token\", accessToken);\r\n setPassword(SERVICE_NAME, \"refresh_token\", refreshToken);\r\n setPassword(SERVICE_NAME, \"user_metadata\", JSON.stringify(user));\r\n }\r\n\r\n /**\r\n * Get stored user metadata\r\n */\r\n async getUserMetadata(): Promise<UserMetadata | null> {\r\n try {\r\n const metadata = getPassword(SERVICE_NAME, \"user_metadata\");\r\n return metadata ? JSON.parse(metadata) : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Logout - clear all stored credentials\r\n */\r\n async logout(): Promise<void> {\r\n try {\r\n deletePassword(SERVICE_NAME, \"access_token\");\r\n deletePassword(SERVICE_NAME, \"refresh_token\");\r\n deletePassword(SERVICE_NAME, \"user_metadata\");\r\n } catch (error) {\r\n // Ignore errors during logout\r\n }\r\n }\r\n\r\n /**\r\n * Check if user is currently authenticated\r\n */\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await this.getAccessToken();\r\n return token !== null;\r\n }\r\n}\r\n","import axios, { AxiosInstance } from \"axios\";\r\n\r\n// Production API URL (can be overridden via API_URL env for local dev)\r\nconst API_URL = process.env.API_URL || \"https://aerocoding.dev\";\r\n\r\ninterface User {\r\n id: string;\r\n email: string;\r\n name: string | null;\r\n tier: string;\r\n}\r\n\r\ninterface Organization {\r\n id: string;\r\n name: string;\r\n slug: string;\r\n planTier: string;\r\n}\r\n\r\ninterface Project {\r\n id: string;\r\n name: string;\r\n slug: string;\r\n schema: any;\r\n organizationId: string;\r\n backendFramework?: string;\r\n frontendFramework?: string;\r\n createdAt: string;\r\n updatedAt: string;\r\n}\r\n\r\ninterface GeneratePayload {\r\n projectId: string;\r\n // NEW: Use templateId for full architecture generation\r\n templateId?: string;\r\n // Legacy: Use targets for simple generation\r\n targets?: string[];\r\n options?: {\r\n includeValidations?: boolean;\r\n includeComments?: boolean;\r\n includeAnnotations?: boolean;\r\n includeLogging?: boolean;\r\n includeTesting?: boolean;\r\n outputDir?: string;\r\n backendPreset?: string;\r\n frontendPreset?: string;\r\n backendLayers?: string[];\r\n frontendLayers?: string[];\r\n validationLib?: string;\r\n // NEW: Feature flags for template generation\r\n featureFlags?: Record<string, boolean>;\r\n // Architecture style: bounded-contexts vs flat\r\n useContexts?: boolean;\r\n // Filter by diagram/bounded context IDs\r\n diagramIds?: string[];\r\n };\r\n}\r\n\r\ninterface GeneratedFile {\r\n path: string;\r\n content: string;\r\n language: string;\r\n entityId?: string;\r\n}\r\n\r\ninterface GenerateResult {\r\n files: GeneratedFile[];\r\n stats?: {\r\n totalFiles?: number;\r\n totalEntities?: number;\r\n languages?: string[];\r\n };\r\n cliCommand?: string;\r\n warnings?: string[];\r\n creditsUsed?: number;\r\n creditsRemaining?: number;\r\n}\r\n\r\ninterface CreditUsage {\r\n used: number;\r\n limit: number;\r\n bonusCredits: number;\r\n remaining: number;\r\n}\r\n\r\ninterface ArchitectureLayer {\r\n id: string;\r\n name: string;\r\n category: string;\r\n description?: string;\r\n}\r\n\r\ninterface Architecture {\r\n id: string;\r\n name: string;\r\n description: string;\r\n layers: ArchitectureLayer[];\r\n}\r\n\r\n// New Template Registry Types\r\ninterface TemplateMetadata {\r\n id: string;\r\n name: string;\r\n description: string;\r\n category: \"backend\" | \"frontend\" | \"database\" | \"infra\";\r\n language: string;\r\n framework: string;\r\n tier: \"starter\" | \"standard\" | \"enterprise\";\r\n tags: string[];\r\n version: string;\r\n author: string;\r\n isLegacy?: boolean;\r\n isOfficial?: boolean;\r\n isPremium?: boolean;\r\n /** Architecture style: \"bounded-contexts\" for DDD modules, \"flat\" for single structure */\r\n architectureStyle?: \"bounded-contexts\" | \"flat\";\r\n}\r\n\r\ninterface TemplateLayer {\r\n id: string;\r\n name: string;\r\n description: string;\r\n category: string;\r\n enabled: boolean;\r\n}\r\n\r\ninterface TemplateFeatureFlag {\r\n id: string;\r\n name: string;\r\n label: string;\r\n description?: string;\r\n defaultValue: boolean;\r\n}\r\n\r\ninterface FullTemplate extends TemplateMetadata {\r\n layers: TemplateLayer[];\r\n featureFlags: TemplateFeatureFlag[];\r\n enabledModules: string[];\r\n}\r\n\r\ninterface TemplateFilter {\r\n category?: \"backend\" | \"frontend\" | \"database\" | \"infra\";\r\n language?: string;\r\n framework?: string;\r\n tier?: \"starter\" | \"standard\" | \"enterprise\";\r\n tags?: string[];\r\n}\r\n\r\ninterface TemplateSearchResult {\r\n templates: TemplateMetadata[];\r\n total: number;\r\n page: number;\r\n pageSize: number;\r\n}\r\n\r\ninterface TemplateCombination {\r\n id: string;\r\n name: string;\r\n description: string;\r\n backend: string;\r\n frontend: string;\r\n sharedTypes?: boolean;\r\n apiContract?: \"rest\" | \"graphql\" | \"grpc\";\r\n}\r\n\r\ninterface CreditEstimate {\r\n estimatedCredits: number;\r\n totalFiles: number;\r\n files: string[];\r\n entities: number;\r\n}\r\n\r\ninterface EstimatePayload {\r\n projectId: string;\r\n // Template mode (new)\r\n templateId?: string;\r\n // Legacy targets mode\r\n targets?: string[];\r\n options?: {\r\n outputDir?: string;\r\n backendPreset?: string;\r\n frontendPreset?: string;\r\n backendLayers?: string[];\r\n frontendLayers?: string[];\r\n featureFlags?: Record<string, boolean>;\r\n // Architecture style: bounded-contexts vs flat\r\n useContexts?: boolean;\r\n // Filter by diagram/bounded context IDs\r\n diagramIds?: string[];\r\n };\r\n}\r\n\r\n/**\r\n * ApiClient\r\n *\r\n * Authenticated HTTP client for AeroCoding API\r\n * All requests include Bearer token authentication\r\n */\r\nexport class ApiClient {\r\n private client: AxiosInstance;\r\n\r\n constructor(\r\n accessToken: string,\r\n options?: {\r\n onUnauthorized?: () => Promise<void> | void;\r\n }\r\n ) {\r\n this.client = axios.create({\r\n baseURL: API_URL,\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"X-Requested-With\": \"XMLHttpRequest\", // Required for CSRF validation bypass\r\n },\r\n timeout: 30000, // 30 seconds\r\n });\r\n\r\n this.client.interceptors.response.use(\r\n (response) => response,\r\n async (error) => {\r\n if (error?.response?.status === 401) {\r\n await options?.onUnauthorized?.();\r\n }\r\n\r\n return Promise.reject(error);\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * Get current authenticated user\r\n */\r\n async getCurrentUser(): Promise<User> {\r\n const response = await this.client.get(\"/api/user/me\");\r\n return response.data;\r\n }\r\n\r\n /**\r\n * List user's organizations\r\n */\r\n async listOrganizations(): Promise<Organization[]> {\r\n const response = await this.client.get(\"/api/organizations\");\r\n return response.data;\r\n }\r\n\r\n /**\r\n * List user's projects\r\n */\r\n async listProjects(organizationId?: string): Promise<Project[]> {\r\n const response = await this.client.get(\"/api/projects\", {\r\n params: { organizationId },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get project by ID\r\n */\r\n async getProject(projectId: string): Promise<Project> {\r\n const response = await this.client.get(`/api/projects/${projectId}`);\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Generate code from project schema\r\n */\r\n async generateCode(payload: GeneratePayload): Promise<GenerateResult> {\r\n const response = await this.client.post(\"/api/generate\", payload);\r\n return response.data.data;\r\n }\r\n\r\n /**\r\n * Get credit usage for organization\r\n */\r\n async getCreditUsage(organizationId: string): Promise<CreditUsage> {\r\n const response = await this.client.get(\"/api/credits/usage\", {\r\n params: { organizationId },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get available architectures for a framework\r\n */\r\n async getArchitectures(framework: string): Promise<Architecture[]> {\r\n const response = await this.client.get(\"/api/architectures\", {\r\n params: { framework },\r\n });\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Estimate credit cost for a generation request\r\n */\r\n async estimateCreditCost(payload: EstimatePayload): Promise<CreditEstimate> {\r\n const response = await this.client.post(\"/api/generate/estimate\", payload);\r\n return response.data.data;\r\n }\r\n\r\n // ============================================\r\n // Template Registry API\r\n // ============================================\r\n\r\n /**\r\n * Search templates with filters\r\n */\r\n async getTemplates(filter: TemplateFilter = {}): Promise<TemplateSearchResult> {\r\n const params = new URLSearchParams();\r\n if (filter.category) params.set(\"category\", filter.category);\r\n if (filter.language) params.set(\"language\", filter.language);\r\n if (filter.framework) params.set(\"framework\", filter.framework);\r\n if (filter.tier) params.set(\"tier\", filter.tier);\r\n if (filter.tags?.length) params.set(\"tags\", filter.tags.join(\",\"));\r\n\r\n const response = await this.client.get(`/api/templates?${params.toString()}`);\r\n return response.data;\r\n }\r\n\r\n /**\r\n * Get full template by ID (includes layers and feature flags)\r\n */\r\n async getTemplate(id: string): Promise<FullTemplate> {\r\n const response = await this.client.get(`/api/templates/${id}?full=true`);\r\n return response.data.template;\r\n }\r\n\r\n /**\r\n * Get template combinations (backend + frontend pairs)\r\n */\r\n async getTemplateCombinations(): Promise<TemplateCombination[]> {\r\n const response = await this.client.get(\"/api/templates/combinations\");\r\n return response.data.combinations;\r\n }\r\n\r\n /**\r\n * Get templates compatible with a given template\r\n */\r\n async getCompatibleTemplates(templateId: string): Promise<TemplateMetadata[]> {\r\n const response = await this.client.get(`/api/templates/${templateId}?compatible=true`);\r\n return response.data.compatible || [];\r\n }\r\n\r\n // ============================================\r\n // Manifest Cloud Sync API\r\n // ============================================\r\n\r\n /**\r\n * Get manifest from cloud storage\r\n * @returns Manifest or null if not found\r\n */\r\n async getManifest(projectId: string): Promise<CloudManifest | null> {\r\n try {\r\n const response = await this.client.get(`/api/projects/${projectId}/manifest`);\r\n return response.data;\r\n } catch (error: any) {\r\n if (error?.response?.status === 404) {\r\n return null;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Save manifest to cloud storage\r\n */\r\n async saveManifest(\r\n projectId: string,\r\n manifest: CloudManifest\r\n ): Promise<{ success: boolean; fileCount: number; removedPaths: number }> {\r\n const response = await this.client.put(\r\n `/api/projects/${projectId}/manifest`,\r\n manifest\r\n );\r\n return response.data;\r\n }\r\n}\r\n\r\n// ============================================\r\n// Cloud Manifest Types\r\n// ============================================\r\n\r\nexport interface CloudManifestFileEntry {\r\n hash: string;\r\n mtime: number;\r\n size: number;\r\n entityId?: string;\r\n type?: \"entity\" | \"usecase\" | \"repository\" | \"controller\" | \"dto\" | \"config\" | \"test\" | \"other\";\r\n contextName?: string;\r\n}\r\n\r\nexport interface CloudManifest {\r\n version: string;\r\n lastSync?: string;\r\n templateVersion?: string;\r\n files: Record<string, CloudManifestFileEntry>;\r\n}\r\n","import { ApiClient } from \"../../api/client.js\";\r\nimport { TokenManager } from \"../../auth/token-manager.js\";\r\n\r\nexport function createApiClientWithAutoLogout(\r\n accessToken: string,\r\n tokenManager: TokenManager\r\n): ApiClient {\r\n return new ApiClient(accessToken, {\r\n onUnauthorized: async () => {\r\n await tokenManager.logout();\r\n },\r\n });\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../../auth/token-manager.js\";\r\n\r\nexport async function handleUnauthorized(\r\n tokenManager: TokenManager\r\n): Promise<never> {\r\n await tokenManager.logout();\r\n\r\n console.error(\r\n chalk.yellow(\r\n \" Your session is invalid or expired. You have been logged out.\"\r\n )\r\n );\r\n console.error(chalk.gray(\" Run 'aerocoding login' to authenticate.\"));\r\n\r\n process.exit(1);\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\n\r\n/**\r\n * Logout Command\r\n *\r\n * Clears stored credentials from OS credential manager\r\n */\r\nexport async function logoutCommand() {\r\n const tokenManager = new TokenManager();\r\n\r\n const metadata = await tokenManager.getUserMetadata();\r\n if (!metadata) {\r\n console.log(chalk.yellow(\"Not logged in\"));\r\n return;\r\n }\r\n\r\n const email = metadata.email;\r\n\r\n await tokenManager.logout();\r\n\r\n console.log(chalk.green(\"Logged out successfully\"));\r\n console.log(chalk.gray(` Cleared credentials for ${email}\\n`));\r\n}\r\n","import chalk from \"chalk\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\n\r\n/**\r\n * Whoami Command\r\n *\r\n * Shows current authenticated user information\r\n */\r\nexport async function whoamiCommand() {\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n console.log(chalk.red(\"Not logged in\"));\r\n console.log(chalk.gray(\" Run 'aerocoding login' to authenticate\\n\"));\r\n return;\r\n }\r\n\r\n try {\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n const user = await apiClient.getCurrentUser();\r\n\r\n console.log(\"\");\r\n console.log(chalk.white(\"Logged in as:\"), chalk.cyan.bold(user.email));\r\n if (user.name) {\r\n console.log(chalk.gray(\" Name:\"), user.name);\r\n }\r\n console.log(\"\");\r\n } catch (error: any) {\r\n console.error(chalk.red(\"Failed to get user info\"));\r\n if (error.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n","import * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport { mkdir, access } from \"node:fs/promises\";\r\nimport { resolve } from \"node:path\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\nimport { writeGeneratedFiles, categorizeFilePaths } from \"../utils/file-writer.js\";\r\nimport {\r\n createProjectConfig,\r\n saveProjectConfig,\r\n PROJECT_CONFIG_FILENAME,\r\n} from \"../config/project-config.js\";\r\nimport {\r\n createEmptyManifest,\r\n writeManifest,\r\n setManifestFile,\r\n hashString,\r\n MANIFEST_FILENAME,\r\n type AeroManifest,\r\n} from \"../manifest/index.js\";\r\nimport { syncToCloud } from \"../utils/cloud-sync.js\";\r\n\r\ninterface CreateOptions {\r\n template?: string;\r\n project?: string;\r\n force?: boolean;\r\n}\r\n\r\n/**\r\n * Create Command\r\n *\r\n * Creates a new AeroCoding project with full architecture generation.\r\n * Combines init + generate into a single command for the meta-framework approach.\r\n *\r\n * Flow:\r\n * 1. Interactive setup (select org, project, template)\r\n * 2. Infer directory name from project (or use provided name)\r\n * 3. Generate full architecture\r\n * 4. Create aerocoding.json + aerocoding-manifest.json\r\n */\r\nexport async function createCommand(projectName: string | undefined, options: CreateOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Create \"));\r\n\r\n // 1. Check authentication first\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n p.cancel(\"Not logged in. Run 'aerocoding login' first.\");\r\n process.exit(1);\r\n }\r\n\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n\r\n try {\r\n // 2. Select organization\r\n const orgSpinner = p.spinner();\r\n orgSpinner.start(\"Loading organizations...\");\r\n\r\n const organizations = await apiClient.listOrganizations();\r\n orgSpinner.stop(\"Organizations loaded\");\r\n\r\n if (organizations.length === 0) {\r\n p.cancel(\"No organizations found. Create one on aerocoding.dev first.\");\r\n process.exit(1);\r\n }\r\n\r\n let organizationId: string;\r\n\r\n if (organizations.length === 1 && organizations[0]) {\r\n organizationId = organizations[0].id;\r\n p.log.info(`Organization: ${organizations[0].name}`);\r\n } else {\r\n const selectedOrg = await p.select({\r\n message: \"Select organization\",\r\n options: organizations.map((org) => ({\r\n value: org.id,\r\n label: org.name,\r\n hint: org.planTier.toUpperCase(),\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedOrg)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n organizationId = selectedOrg as string;\r\n }\r\n\r\n // 3. Select project (or use provided --project)\r\n let projectId = options.project;\r\n\r\n if (!projectId) {\r\n const spinner = p.spinner();\r\n spinner.start(\"Loading projects...\");\r\n\r\n const projects = await apiClient.listProjects(organizationId);\r\n spinner.stop(\"Projects loaded\");\r\n\r\n if (projects.length === 0) {\r\n p.cancel(\"No projects in this organization. Create one on aerocoding.dev first.\");\r\n process.exit(1);\r\n }\r\n\r\n const selectedProject = await p.select({\r\n message: \"Select project to generate from\",\r\n options: projects.map((proj) => ({\r\n value: proj.id,\r\n label: proj.name,\r\n hint: [proj.backendFramework, proj.frontendFramework].filter(Boolean).join(\" + \"),\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedProject)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n projectId = selectedProject as string;\r\n }\r\n\r\n // 4. Fetch project details\r\n const projectSpinner = p.spinner();\r\n projectSpinner.start(\"Fetching project details...\");\r\n const project = await apiClient.getProject(projectId);\r\n projectSpinner.stop(`Project: ${project.name}`);\r\n\r\n // 5. Determine directory name (from argument or project name)\r\n const dirName = projectName || project.name;\r\n const safeName = dirName\r\n .toLowerCase()\r\n .replace(/[^a-z0-9-]/g, \"-\")\r\n .replace(/-+/g, \"-\")\r\n .replace(/^-|-$/g, \"\");\r\n\r\n if (!safeName) {\r\n p.cancel(\"Invalid project name. Use alphanumeric characters and hyphens.\");\r\n process.exit(1);\r\n }\r\n\r\n const projectDir = resolve(process.cwd(), safeName);\r\n\r\n // Check if directory already exists\r\n try {\r\n await access(projectDir);\r\n if (!options.force) {\r\n const overwrite = await p.confirm({\r\n message: `Directory '${safeName}' already exists. Overwrite?`,\r\n initialValue: false,\r\n });\r\n\r\n if (p.isCancel(overwrite) || !overwrite) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n } catch {\r\n // Directory doesn't exist, good\r\n }\r\n\r\n // 5. Select template\r\n let templateId = options.template;\r\n\r\n if (!templateId) {\r\n const templateSpinner = p.spinner();\r\n templateSpinner.start(\"Loading templates...\");\r\n\r\n // Get backend templates if project has backend\r\n const templateResult = await apiClient.getTemplates({\r\n category: \"backend\",\r\n language: project.backendFramework || undefined,\r\n });\r\n\r\n templateSpinner.stop(\"Templates loaded\");\r\n\r\n if (templateResult.templates.length === 0) {\r\n p.cancel(\"No templates available for this project's framework.\");\r\n process.exit(1);\r\n }\r\n\r\n const selectedTemplate = await p.select({\r\n message: \"Select architecture template\",\r\n options: templateResult.templates.map((tmpl) => ({\r\n value: tmpl.id,\r\n label: tmpl.name,\r\n hint: tmpl.description || `${tmpl.tier} tier`,\r\n })),\r\n });\r\n\r\n if (p.isCancel(selectedTemplate)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n templateId = selectedTemplate as string;\r\n }\r\n\r\n // 6. Bounded Context selection (if multiple diagrams exist)\r\n interface Diagram {\r\n id?: string;\r\n name?: string;\r\n entities?: unknown[];\r\n }\r\n const diagrams: Diagram[] = (project.schema as { diagrams?: Diagram[] })?.diagrams || [];\r\n const hasMultipleDiagrams = diagrams.length > 1;\r\n\r\n let selectedDiagramIds: string[] = diagrams.map((d) => d.id || d.name || \"unknown\");\r\n\r\n if (hasMultipleDiagrams) {\r\n const diagramChoices = await p.multiselect({\r\n message: \"Which bounded contexts do you want to generate?\",\r\n options: diagrams.map((d) => ({\r\n value: d.id || d.name || \"unknown\",\r\n label: `${d.name || \"Unnamed\"} (${d.entities?.length || 0} entities)`,\r\n })),\r\n initialValues: diagrams.map((d) => d.id || d.name || \"unknown\"),\r\n required: true,\r\n });\r\n\r\n if (p.isCancel(diagramChoices)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n selectedDiagramIds = diagramChoices as string[];\r\n }\r\n\r\n // 7. Get namespace\r\n const namespace = await p.text({\r\n message: \"Root namespace/package name\",\r\n placeholder: \"MegaStore\",\r\n initialValue: toPascalCase(project.name),\r\n validate: (value) => {\r\n if (!value || value.trim() === \"\") return \"Namespace is required\";\r\n if (!/^[A-Za-z][A-Za-z0-9]*$/.test(value)) {\r\n return \"Namespace must start with a letter and contain only alphanumeric characters\";\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (p.isCancel(namespace)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n // 8. Architecture style selection\r\n const archStyleChoice = await p.select({\r\n message: \"Architecture style\",\r\n options: [\r\n {\r\n value: \"bounded-contexts\",\r\n label: \"Bounded Contexts\",\r\n hint: \"DDD-style: separate folders per module (recommended)\",\r\n },\r\n {\r\n value: \"flat\",\r\n label: \"Flat Structure\", \r\n hint: \"All layers in single structure (simpler)\",\r\n },\r\n ],\r\n initialValue: \"bounded-contexts\",\r\n });\r\n\r\n if (p.isCancel(archStyleChoice)) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n const useContexts = archStyleChoice === \"bounded-contexts\";\r\n\r\n // 9. Get credit estimate with file preview BEFORE confirmation\r\n const estimateSpinner = p.spinner();\r\n estimateSpinner.start(\"Calculating credit cost...\");\r\n\r\n let estimatedCredits = 0;\r\n let creditsRemaining = 0;\r\n let estimatedFiles: string[] = [];\r\n let estimatedEntities = 0;\r\n\r\n // Include diagramIds to filter estimate by selected bounded contexts\r\n const estimateDiagramIds = selectedDiagramIds.length < diagrams.length ? selectedDiagramIds : undefined;\r\n\r\n try {\r\n const estimate = await apiClient.estimateCreditCost({\r\n projectId,\r\n templateId,\r\n options: {\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: true,\r\n includeReactions: true,\r\n includeOutbox: true,\r\n includeInbox: true,\r\n },\r\n useContexts,\r\n diagramIds: estimateDiagramIds,\r\n },\r\n });\r\n\r\n estimatedCredits = estimate.estimatedCredits;\r\n estimatedFiles = estimate.files || [];\r\n estimatedEntities = estimate.entities || 0;\r\n \r\n // Get remaining credits\r\n const creditUsage = await apiClient.getCreditUsage(organizationId);\r\n creditsRemaining = creditUsage.remaining;\r\n \r\n estimateSpinner.stop(\"Credit estimate calculated\");\r\n } catch {\r\n estimateSpinner.stop(\"Could not estimate credits (will be calculated on generation)\");\r\n }\r\n\r\n // Check if enough credits before proceeding\r\n const hasEnoughCredits = estimatedCredits === 0 || creditsRemaining >= estimatedCredits;\r\n\r\n // 9. Show beautiful summary (like old generate command)\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Generation Summary\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n console.log(chalk.gray(\" Project:\"), chalk.white(project.name));\r\n console.log(chalk.gray(\" Template:\"), chalk.cyan(templateId));\r\n console.log(chalk.gray(\" Namespace:\"), chalk.cyan(namespace));\r\n console.log(chalk.gray(\" Directory:\"), chalk.cyan(`${safeName}/`));\r\n console.log(\r\n chalk.gray(\" Architecture:\"),\r\n useContexts ? chalk.cyan(\"Bounded Contexts\") : chalk.yellow(\"Flat Structure\")\r\n );\r\n\r\n // Show selected bounded contexts (if user had a choice)\r\n if (hasMultipleDiagrams) {\r\n const selectedCount = selectedDiagramIds.length;\r\n const totalCount = diagrams.length;\r\n if (selectedCount === totalCount) {\r\n console.log(chalk.gray(\" Bounded Contexts:\"), chalk.cyan(`All (${totalCount})`));\r\n } else {\r\n const selectedNames = diagrams\r\n .filter((d) => selectedDiagramIds.includes(d.id || d.name || \"unknown\"))\r\n .map((d) => d.name || \"Unnamed\")\r\n .join(\", \");\r\n console.log(chalk.gray(\" Bounded Contexts:\"), chalk.cyan(`${selectedCount}/${totalCount} (${selectedNames})`));\r\n }\r\n }\r\n\r\n // Show file preview by category (if available)\r\n if (estimatedFiles.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Files to Generate\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n const categories = categorizeFilePaths(estimatedFiles);\r\n const maxNameLength = Math.max(...categories.map((c) => c.name.length));\r\n\r\n for (const category of categories) {\r\n const padding = \" \".repeat(maxNameLength - category.name.length + 2);\r\n const countStr = category.count.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.gray(` ${category.name}${padding}`),\r\n chalk.cyan(`${countStr} files`)\r\n );\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n const totalPadding = \" \".repeat(maxNameLength - 5 + 2);\r\n const totalStr = estimatedFiles.length.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.white(` Total${totalPadding}`),\r\n chalk.bold.cyan(`${totalStr} files`)\r\n );\r\n console.log(chalk.gray(\" Entities:\"), chalk.cyan(estimatedEntities));\r\n }\r\n\r\n // Show credits section\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Credits\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n if (estimatedCredits > 0) {\r\n console.log(\r\n chalk.white(\" Cost:\"),\r\n hasEnoughCredits\r\n ? chalk.bold.yellow(`${estimatedCredits} credits`)\r\n : chalk.bold.red(`${estimatedCredits} credits`)\r\n );\r\n }\r\n console.log(\r\n chalk.white(\" Available:\"),\r\n hasEnoughCredits\r\n ? chalk.bold.green(`${creditsRemaining} credits`)\r\n : chalk.bold.red(`${creditsRemaining} credits (insufficient)`)\r\n );\r\n console.log(\"\");\r\n\r\n // Warn if not enough credits\r\n if (!hasEnoughCredits) {\r\n console.log(chalk.red(\" ⚠ Not enough credits for this generation.\"));\r\n console.log(chalk.gray(` Need ${estimatedCredits - creditsRemaining} more credits.\\n`));\r\n process.exit(1);\r\n }\r\n\r\n const proceed = await p.confirm({\r\n message: estimatedCredits > 0 \r\n ? `Proceed with generation? (~${estimatedCredits} credits)`\r\n : \"Proceed with generation?\",\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Operation cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n // 8. Create directory\r\n const dirSpinner = p.spinner();\r\n dirSpinner.start(`Creating ${safeName}/...`);\r\n await mkdir(projectDir, { recursive: true });\r\n dirSpinner.stop(`Created ${safeName}/`);\r\n\r\n // 9. Generate code\r\n const genSpinner = ora({ text: \"Generating architecture...\", color: \"cyan\" }).start();\r\n\r\n const result = await apiClient.generateCode({\r\n projectId,\r\n templateId,\r\n options: {\r\n includeValidations: true,\r\n includeComments: true,\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: true,\r\n includeReactions: true,\r\n includeOutbox: true,\r\n includeInbox: true,\r\n },\r\n useContexts,\r\n diagramIds: estimateDiagramIds, // Filter by selected bounded contexts\r\n },\r\n });\r\n\r\n genSpinner.succeed(chalk.green(`Generated ${result.files?.length || 0} files`));\r\n\r\n // 10. Write files to project directory\r\n const writeSpinner = p.spinner();\r\n writeSpinner.start(\"Writing files...\");\r\n\r\n // Organize files into backend folder\r\n const organizedFiles = result.files.map((file: { path: string; content: string; language: string }) => ({\r\n ...file,\r\n path: `backend/${file.path}`,\r\n }));\r\n\r\n await writeGeneratedFiles(organizedFiles, projectDir, false);\r\n writeSpinner.stop(`Wrote ${organizedFiles.length} files`);\r\n\r\n // 11. Create aerocoding.json\r\n const configSpinner = p.spinner();\r\n configSpinner.start(\"Creating config files...\");\r\n\r\n const projectConfig = createProjectConfig({\r\n projectId,\r\n templateId,\r\n templateVersion: \"1.0.0\", // TODO: get from template\r\n namespace: namespace as string,\r\n organizationId,\r\n output: { backend: \"./backend\", frontend: \"./frontend\" },\r\n });\r\n\r\n await saveProjectConfig(projectConfig, projectDir);\r\n\r\n // 12. Create aerocoding-manifest.json\r\n let manifest: AeroManifest = createEmptyManifest(\"1.0.0\");\r\n\r\n // Track all generated files in manifest\r\n for (const file of organizedFiles) {\r\n const hash = hashString(file.content);\r\n manifest = setManifestFile(manifest, file.path, {\r\n hash,\r\n mtime: Date.now(),\r\n size: Buffer.byteLength(file.content, \"utf-8\"),\r\n type: detectFileType(file.path),\r\n });\r\n }\r\n\r\n await writeManifest(projectDir, manifest);\r\n configSpinner.stop(\"Config files created\");\r\n\r\n // 13. Sync manifest to cloud\r\n try {\r\n const syncResult = await syncToCloud(apiClient, projectId, manifest);\r\n if (syncResult.success) {\r\n console.log(\r\n chalk.gray(\" ✓ Manifest synced to cloud\") +\r\n chalk.gray(` (${syncResult.fileCount} files)`)\r\n );\r\n }\r\n } catch {\r\n // Non-fatal - just log warning\r\n console.log(chalk.yellow(\" ⚠ Could not sync manifest to cloud\"));\r\n }\r\n\r\n // 14. Show results\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Project Created Successfully!\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n console.log(chalk.gray(\" Directory:\"), chalk.cyan(safeName + \"/\"));\r\n console.log(chalk.gray(\" Files:\"), chalk.cyan(organizedFiles.length));\r\n console.log(chalk.gray(\" Config:\"), chalk.cyan(PROJECT_CONFIG_FILENAME));\r\n console.log(chalk.gray(\" Manifest:\"), chalk.cyan(MANIFEST_FILENAME));\r\n\r\n if (result.creditsUsed !== undefined) {\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Credits used:\"), chalk.yellow(result.creditsUsed));\r\n console.log(chalk.gray(\" Credits remaining:\"), chalk.green(result.creditsRemaining));\r\n }\r\n\r\n p.outro(\r\n chalk.green(\"Project ready!\") +\r\n \"\\n\\n\" +\r\n chalk.gray(\" Next steps:\\n\") +\r\n chalk.cyan(` cd ${safeName}\\n`) +\r\n chalk.gray(\" # Make changes in the diagram editor\\n\") +\r\n chalk.cyan(\" aerocoding update\") +\r\n chalk.gray(\" # Sync changes incrementally\")\r\n );\r\n } catch (error: unknown) {\r\n const err = error as { response?: { status?: number; data?: { message?: string } }; message?: string };\r\n if (err.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n } else if (err.response?.data?.message) {\r\n p.cancel(err.response.data.message);\r\n } else {\r\n p.cancel(err.message || \"An unexpected error occurred\");\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/**\r\n * Convert string to PascalCase for .NET namespaces\r\n * \"mega-store\" → \"MegaStore\"\r\n * \"mega_store\" → \"MegaStore\"\r\n * \"mega store\" → \"MegaStore\"\r\n */\r\nfunction toPascalCase(str: string): string {\r\n return str\r\n .split(/[-_\\s]+/) // Split by hyphen, underscore, or space\r\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\r\n .join(\"\")\r\n .replace(/[^a-zA-Z0-9]/g, \"\"); // Remove any remaining special chars\r\n}\r\n\r\n/**\r\n * Detect file type from path for manifest categorization\r\n */\r\nfunction detectFileType(\r\n filePath: string\r\n): \"entity\" | \"usecase\" | \"repository\" | \"controller\" | \"dto\" | \"config\" | \"test\" | \"other\" {\r\n const lower = filePath.toLowerCase();\r\n\r\n if (lower.includes(\"/entities/\") || lower.includes(\"/domain/\")) return \"entity\";\r\n if (lower.includes(\"/usecases/\") || lower.includes(\"/application/\")) return \"usecase\";\r\n if (lower.includes(\"/repositories/\")) return \"repository\";\r\n if (lower.includes(\"/controllers/\") || lower.includes(\"/api/\")) return \"controller\";\r\n if (lower.includes(\"/dtos/\") || lower.includes(\"/dto/\")) return \"dto\";\r\n if (lower.includes(\".test.\") || lower.includes(\".spec.\") || lower.includes(\"/tests/\")) return \"test\";\r\n if (lower.includes(\"/config/\") || lower.includes(\"appsettings\") || lower.includes(\".csproj\")) return \"config\";\r\n\r\n return \"other\";\r\n}\r\n","import fs from \"fs/promises\";\r\nimport path from \"path\";\r\nimport chalk from \"chalk\";\r\nimport type { AeroManifest, ManifestFileEntry } from \"../manifest/index.js\";\r\nimport {\r\n createEmptyManifest,\r\n setManifestFile,\r\n writeManifest,\r\n readManifest,\r\n detectFileChange,\r\n hashString,\r\n} from \"../manifest/index.js\";\r\nimport {\r\n performMerge,\r\n writeConflictFiles,\r\n} from \"../merge/index.js\";\r\n\r\ninterface GeneratedFile {\r\n path: string;\r\n content: string;\r\n language: string;\r\n entityId?: string;\r\n /**\r\n * If true, file should only be written if it doesn't already exist.\r\n * Used for starter files (Program.cs, appsettings.json) that users may customize.\r\n */\r\n generateOnce?: boolean;\r\n /**\r\n * File type for manifest categorization\r\n */\r\n type?: ManifestFileEntry['type'];\r\n /**\r\n * Bounded context name for DDD organization\r\n */\r\n contextName?: string;\r\n}\r\n\r\n/**\r\n * Result of writing files with manifest tracking\r\n */\r\nexport interface WriteResult {\r\n created: string[];\r\n updated: string[];\r\n merged: string[];\r\n skipped: string[];\r\n conflicts: Array<{\r\n path: string;\r\n reason: string;\r\n newPath?: string;\r\n conflictPath?: string;\r\n }>;\r\n manifest: AeroManifest;\r\n}\r\n\r\nexport interface FileCategory {\r\n name: string;\r\n count: number;\r\n files: string[];\r\n}\r\n\r\n/**\r\n * Validate that a file path is safe and doesn't escape the output directory.\r\n * SECURITY: Prevents path traversal attacks (e.g., ../../../etc/passwd)\r\n */\r\nfunction isPathSafe(outputDir: string, filePath: string): boolean {\r\n // Resolve both paths to absolute paths\r\n const resolvedOutput = path.resolve(outputDir);\r\n const resolvedFile = path.resolve(outputDir, filePath);\r\n\r\n // Check if the resolved file path starts with the output directory\r\n // Also ensure there's a path separator after the base to prevent\r\n // matching \"output\" when file is in \"output-malicious\"\r\n return (\r\n resolvedFile.startsWith(resolvedOutput + path.sep) ||\r\n resolvedFile === resolvedOutput\r\n );\r\n}\r\n\r\n/**\r\n * Get category name from file path\r\n * Analyzes path segments to determine file type\r\n * @public Exported for use in preview/estimate display\r\n */\r\nexport function getCategoryFromPath(filePath: string): string {\r\n const lowerPath = filePath.toLowerCase();\r\n\r\n // Order matters - more specific first\r\n if (lowerPath.includes(\"/controllers/\")) return \"Controllers\";\r\n if (lowerPath.includes(\"/usecases/\") || lowerPath.includes(\"/use-cases/\"))\r\n return \"UseCases\";\r\n if (lowerPath.includes(\"/dtos/\") || lowerPath.includes(\"/dto/\")) return \"DTOs\";\r\n if (lowerPath.includes(\"/entities/\")) return \"Entities\";\r\n if (\r\n lowerPath.includes(\"/repositories/\") ||\r\n lowerPath.includes(\"/repositoriesimpl/\")\r\n )\r\n return \"Repositories\";\r\n if (\r\n lowerPath.includes(\"/configurations/\") ||\r\n lowerPath.includes(\"/config/\")\r\n )\r\n return \"Configurations\";\r\n if (\r\n lowerPath.includes(\"/validators/\") ||\r\n lowerPath.includes(\"/validation/\")\r\n )\r\n return \"Validators\";\r\n if (lowerPath.includes(\"/mappers/\")) return \"Mappers\";\r\n if (lowerPath.includes(\"/interfaces/\")) return \"Interfaces\";\r\n if (lowerPath.includes(\"/exceptions/\")) return \"Exceptions\";\r\n if (lowerPath.includes(\"/vos/\") || lowerPath.includes(\"/valueobjects/\"))\r\n return \"ValueObjects\";\r\n if (lowerPath.includes(\"/ioc/\") || lowerPath.includes(\"/di/\"))\r\n return \"DependencyInjection\";\r\n if (\r\n lowerPath.includes(\"/tests/\") ||\r\n lowerPath.includes(\".test.\") ||\r\n lowerPath.includes(\".spec.\")\r\n )\r\n return \"Tests\";\r\n if (lowerPath.includes(\"/database/\")) return \"Database\";\r\n\r\n return \"Other\";\r\n}\r\n\r\n/**\r\n * Categorize file paths into categories\r\n * Used for preview/estimate display before generation\r\n * @public Exported for use in generate command preview\r\n */\r\nexport function categorizeFilePaths(filePaths: string[]): FileCategory[] {\r\n const categories = new Map<string, string[]>();\r\n\r\n for (const filePath of filePaths) {\r\n const category = getCategoryFromPath(filePath);\r\n const existing = categories.get(category) || [];\r\n existing.push(filePath);\r\n categories.set(category, existing);\r\n }\r\n\r\n return Array.from(categories.entries())\r\n .map(([name, fileList]) => ({ name, count: fileList.length, files: fileList }))\r\n .sort((a, b) => b.count - a.count); // Most files first\r\n}\r\n\r\n/**\r\n * Categorize files by their path\r\n * Groups files into categories like Entities, DTOs, UseCases, etc.\r\n */\r\nfunction categorizeFiles(files: GeneratedFile[]): FileCategory[] {\r\n return categorizeFilePaths(files.map((f) => f.path));\r\n}\r\n\r\n/**\r\n * Display categorized summary of generated files\r\n */\r\nfunction displayCategorizedSummary(files: GeneratedFile[]): void {\r\n const categories = categorizeFiles(files);\r\n\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Generated Files\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n // Find max name length for alignment\r\n const maxNameLength = Math.max(...categories.map((c) => c.name.length));\r\n\r\n for (const category of categories) {\r\n const padding = \" \".repeat(maxNameLength - category.name.length + 2);\r\n const countStr = category.count.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.gray(` ${category.name}${padding}`),\r\n chalk.cyan(`${countStr} files`)\r\n );\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n const totalPadding = \" \".repeat(maxNameLength - 5 + 2);\r\n const totalStr = files.length.toString().padStart(3, \" \");\r\n console.log(\r\n chalk.white(` Total${totalPadding}`),\r\n chalk.bold.cyan(`${totalStr} files`)\r\n );\r\n}\r\n\r\n/**\r\n * Write generated files to disk\r\n *\r\n * Creates directories as needed and writes files\r\n * Shows categorized summary by default, or full list with verbose=true\r\n */\r\nexport async function writeGeneratedFiles(\r\n files: GeneratedFile[],\r\n outputDir: string,\r\n verbose: boolean = false\r\n): Promise<void> {\r\n // Track written files for summary\r\n const writtenFiles: GeneratedFile[] = [];\r\n\r\n // Track skipped generateOnce files for summary\r\n const skippedOnceFiles: string[] = [];\r\n\r\n for (const file of files) {\r\n // SECURITY: Validate path doesn't escape output directory\r\n if (!isPathSafe(outputDir, file.path)) {\r\n console.error(chalk.red(` Skipping unsafe path: ${file.path}`));\r\n console.error(\r\n chalk.gray(\r\n ` Path traversal detected - file path must be within output directory`\r\n )\r\n );\r\n continue;\r\n }\r\n\r\n const fullPath = path.resolve(outputDir, file.path);\r\n const dir = path.dirname(fullPath);\r\n\r\n // Check if file has generateOnce flag and already exists\r\n if (file.generateOnce) {\r\n try {\r\n await fs.access(fullPath);\r\n // File exists - skip it\r\n skippedOnceFiles.push(file.path);\r\n continue;\r\n } catch {\r\n // File doesn't exist - proceed with generation\r\n }\r\n }\r\n\r\n try {\r\n // Create directory if doesn't exist\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Write file\r\n await fs.writeFile(fullPath, file.content, \"utf-8\");\r\n\r\n // Show file path in verbose mode\r\n if (verbose) {\r\n console.log(chalk.gray(` ${file.path}`));\r\n }\r\n\r\n writtenFiles.push(file);\r\n } catch (error: any) {\r\n console.error(chalk.red(` Failed to write ${file.path}`));\r\n console.error(chalk.gray(` ${error.message}`));\r\n }\r\n }\r\n\r\n // Show categorized summary (unless verbose)\r\n if (!verbose && writtenFiles.length > 0) {\r\n displayCategorizedSummary(writtenFiles);\r\n }\r\n\r\n // Show skipped generateOnce files\r\n if (skippedOnceFiles.length > 0) {\r\n console.log(\"\");\r\n console.log(\r\n chalk.gray(` Skipped ${skippedOnceFiles.length} existing file(s) (generateOnce):`)\r\n );\r\n for (const filePath of skippedOnceFiles) {\r\n console.log(chalk.gray(` - ${filePath}`));\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Infer file type from path for manifest categorization\r\n */\r\nfunction inferFileType(filePath: string): ManifestFileEntry['type'] {\r\n const lowerPath = filePath.toLowerCase();\r\n\r\n if (lowerPath.includes('/entities/')) return 'entity';\r\n if (lowerPath.includes('/usecases/') || lowerPath.includes('/use-cases/')) return 'usecase';\r\n if (lowerPath.includes('/repositories/')) return 'repository';\r\n if (lowerPath.includes('/controllers/')) return 'controller';\r\n if (lowerPath.includes('/dtos/') || lowerPath.includes('/dto/')) return 'dto';\r\n if (lowerPath.includes('/tests/') || lowerPath.includes('.test.') || lowerPath.includes('.spec.')) return 'test';\r\n if (lowerPath.includes('/config') || lowerPath.includes('appsettings')) return 'config';\r\n\r\n return 'other';\r\n}\r\n\r\n/**\r\n * Write generated files to disk with manifest tracking\r\n *\r\n * This is the incremental-aware version that:\r\n * 1. Checks if files have been modified by user (via manifest)\r\n * 2. Only overwrites unmodified files\r\n * 3. Flags conflicts for user-modified files\r\n * 4. Updates manifest with new file hashes\r\n */\r\nexport async function writeGeneratedFilesWithManifest(\r\n files: GeneratedFile[],\r\n outputDir: string,\r\n templateVersion: string,\r\n options: {\r\n verbose?: boolean;\r\n forceOverwrite?: boolean;\r\n } = {}\r\n): Promise<WriteResult> {\r\n const { verbose = false, forceOverwrite = false } = options;\r\n\r\n // Load existing manifest or create new one\r\n let manifest = await readManifest(outputDir) || createEmptyManifest(templateVersion);\r\n\r\n const result: WriteResult = {\r\n created: [],\r\n updated: [],\r\n merged: [],\r\n skipped: [],\r\n conflicts: [],\r\n manifest,\r\n };\r\n\r\n for (const file of files) {\r\n // SECURITY: Validate path doesn't escape output directory\r\n if (!isPathSafe(outputDir, file.path)) {\r\n console.error(chalk.red(` Skipping unsafe path: ${file.path}`));\r\n continue;\r\n }\r\n\r\n const fullPath = path.resolve(outputDir, file.path);\r\n const dir = path.dirname(fullPath);\r\n const manifestEntry = manifest.files[file.path];\r\n\r\n // Detect if file has changed\r\n const changeStatus = await detectFileChange(fullPath, manifestEntry);\r\n\r\n let shouldWrite = false;\r\n let action: 'create' | 'update' | 'skip' | 'conflict' = 'skip';\r\n\r\n switch (changeStatus.status) {\r\n case 'new':\r\n // File doesn't exist - create it\r\n shouldWrite = true;\r\n action = 'create';\r\n break;\r\n\r\n case 'unchanged':\r\n // File exists but wasn't modified by user - safe to overwrite\r\n shouldWrite = true;\r\n action = 'update';\r\n break;\r\n\r\n case 'modified':\r\n // File was modified by user - try three-way merge\r\n if (forceOverwrite) {\r\n shouldWrite = true;\r\n action = 'update';\r\n } else {\r\n // Perform three-way merge\r\n const currentContent = await fs.readFile(fullPath, 'utf-8');\r\n\r\n // Get base content from what we last generated (stored hash matches original)\r\n // We need to regenerate base from the hash... but we only have the hash.\r\n // For now, use the generated content as base if this is an update scenario.\r\n // In a proper implementation, we'd store the original content or retrieve it.\r\n //\r\n // Since we don't have the original base content stored, we'll use a simplified approach:\r\n // - If the generated content is the same as before (hash matches), skip\r\n // - Otherwise, try merge with empty base (essentially a diff)\r\n\r\n // For Phase 2, we use the manifest hash to detect changes but can't do true 3-way merge\r\n // without storing base content. For now, generate conflict files.\r\n const mergeResult = performMerge(\r\n manifestEntry?.hash ? '' : '', // We don't have base content stored\r\n currentContent,\r\n file.content\r\n );\r\n\r\n if (mergeResult.success) {\r\n // Merge succeeded - write merged content\r\n shouldWrite = true;\r\n action = 'update';\r\n // Override file.content with merged result\r\n (file as any)._mergedContent = mergeResult.content;\r\n result.merged.push(file.path);\r\n } else {\r\n // Merge has conflicts - write .new and .conflict files\r\n action = 'conflict';\r\n\r\n // Create directory if needed\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Write conflict files\r\n const { newPath, conflictPath } = await writeConflictFiles(\r\n fullPath,\r\n file.content,\r\n mergeResult.conflicts,\r\n currentContent\r\n );\r\n\r\n result.conflicts.push({\r\n path: file.path,\r\n reason: 'Merge conflict - manual resolution required',\r\n newPath: path.relative(outputDir, newPath),\r\n conflictPath: path.relative(outputDir, conflictPath),\r\n });\r\n }\r\n }\r\n break;\r\n\r\n case 'deleted':\r\n // File was in manifest but deleted by user - skip it\r\n action = 'skip';\r\n result.skipped.push(file.path);\r\n break;\r\n\r\n case 'unknown':\r\n // File exists but not in manifest (user created it outside AeroCoding)\r\n action = 'skip';\r\n result.skipped.push(file.path);\r\n break;\r\n }\r\n\r\n // Handle generateOnce files\r\n if (file.generateOnce && changeStatus.status !== 'new') {\r\n shouldWrite = false;\r\n action = 'skip';\r\n if (!result.skipped.includes(file.path)) {\r\n result.skipped.push(file.path);\r\n }\r\n }\r\n\r\n if (shouldWrite) {\r\n try {\r\n // Create directory if doesn't exist\r\n await fs.mkdir(dir, { recursive: true });\r\n\r\n // Use merged content if available, otherwise original\r\n const contentToWrite = (file as any)._mergedContent || file.content;\r\n\r\n // Write file\r\n await fs.writeFile(fullPath, contentToWrite, \"utf-8\");\r\n\r\n // Get file stats for manifest\r\n const stats = await fs.stat(fullPath);\r\n\r\n // Update manifest entry\r\n const entry: ManifestFileEntry = {\r\n hash: hashString(contentToWrite),\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n entityId: file.entityId,\r\n type: file.type || inferFileType(file.path),\r\n contextName: file.contextName,\r\n };\r\n\r\n manifest = setManifestFile(manifest, file.path, entry);\r\n\r\n // Track result based on action\r\n const isMerged = result.merged.includes(file.path);\r\n if (action === 'create') {\r\n result.created.push(file.path);\r\n if (verbose) {\r\n console.log(chalk.green(` ✓ Created ${file.path}`));\r\n }\r\n } else if (isMerged) {\r\n // Already added to merged array\r\n if (verbose) {\r\n console.log(chalk.magenta(` ✓ Merged ${file.path}`));\r\n }\r\n } else {\r\n result.updated.push(file.path);\r\n if (verbose) {\r\n console.log(chalk.blue(` ✓ Updated ${file.path}`));\r\n }\r\n }\r\n } catch (error: any) {\r\n console.error(chalk.red(` Failed to write ${file.path}`));\r\n console.error(chalk.gray(` ${error.message}`));\r\n }\r\n } else if (action === 'conflict' && verbose) {\r\n console.log(chalk.yellow(` ⚠ Conflict ${file.path}`));\r\n }\r\n }\r\n\r\n // Update manifest timestamp and save\r\n manifest = {\r\n ...manifest,\r\n lastSync: new Date().toISOString(),\r\n templateVersion,\r\n };\r\n\r\n await writeManifest(outputDir, manifest);\r\n result.manifest = manifest;\r\n\r\n // Show summary\r\n if (!verbose) {\r\n displayIncrementalSummary(result);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Display summary of incremental write operation\r\n */\r\nfunction displayIncrementalSummary(result: WriteResult): void {\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Update Results\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (result.created.length > 0) {\r\n console.log(chalk.green(` ✓ Created: ${result.created.length} files`));\r\n }\r\n if (result.updated.length > 0) {\r\n console.log(chalk.blue(` ✓ Updated: ${result.updated.length} files`));\r\n }\r\n if (result.merged.length > 0) {\r\n console.log(chalk.magenta(` ✓ Merged: ${result.merged.length} files`));\r\n }\r\n if (result.skipped.length > 0) {\r\n console.log(chalk.gray(` ○ Skipped: ${result.skipped.length} files`));\r\n }\r\n if (result.conflicts.length > 0) {\r\n console.log(chalk.yellow(` ⚠ Conflicts: ${result.conflicts.length} files`));\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n const total = result.created.length + result.updated.length + result.merged.length;\r\n console.log(chalk.white(` Total written: ${total} files`));\r\n\r\n // Show conflict details with file paths\r\n if (result.conflicts.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.yellow(\" ⚠ Conflicts need manual resolution:\"));\r\n console.log(\"\");\r\n\r\n for (const conflict of result.conflicts.slice(0, 5)) {\r\n console.log(chalk.yellow(` ${conflict.path}`));\r\n if (conflict.newPath) {\r\n console.log(chalk.gray(` → ${conflict.newPath}`));\r\n }\r\n if (conflict.conflictPath) {\r\n console.log(chalk.gray(` → ${conflict.conflictPath}`));\r\n }\r\n }\r\n\r\n if (result.conflicts.length > 5) {\r\n console.log(chalk.gray(` ... and ${result.conflicts.length - 5} more`));\r\n }\r\n\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Run 'aerocoding resolve' after fixing conflicts.\"));\r\n }\r\n}\r\n","// ============================================\r\n// Manifest Module\r\n// Public code for tracking generated files\r\n// ============================================\r\n\r\nimport * as fs from 'fs/promises';\r\nimport * as path from 'path';\r\nimport type { AeroManifest, ManifestFileEntry } from './types.js';\r\nimport { MANIFEST_VERSION, MANIFEST_FILENAME } from './types.js';\r\n\r\n// Re-export types\r\nexport type { AeroManifest, ManifestFileEntry, FileChangeStatus } from './types.js';\r\nexport { MANIFEST_VERSION, MANIFEST_FILENAME } from './types.js';\r\n\r\n// Re-export hash utilities\r\nexport { hashString, hashFile, detectFileChange } from './hash-utils.js';\r\n\r\n/**\r\n * Read manifest from a directory\r\n */\r\nexport async function readManifest(projectDir: string): Promise<AeroManifest | null> {\r\n const manifestPath = path.join(projectDir, MANIFEST_FILENAME);\r\n\r\n try {\r\n const content = await fs.readFile(manifestPath, 'utf-8');\r\n return JSON.parse(content) as AeroManifest;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n return null;\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Write manifest to a directory\r\n */\r\nexport async function writeManifest(projectDir: string, manifest: AeroManifest): Promise<void> {\r\n const manifestPath = path.join(projectDir, MANIFEST_FILENAME);\r\n await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\r\n}\r\n\r\n/**\r\n * Create a new empty manifest\r\n */\r\nexport function createEmptyManifest(templateVersion: string): AeroManifest {\r\n return {\r\n version: MANIFEST_VERSION,\r\n lastSync: new Date().toISOString(),\r\n templateVersion,\r\n files: {},\r\n entities: [],\r\n };\r\n}\r\n\r\n/**\r\n * Add or update a file entry in the manifest\r\n */\r\nexport function setManifestFile(\r\n manifest: AeroManifest,\r\n filePath: string,\r\n entry: ManifestFileEntry\r\n): AeroManifest {\r\n return {\r\n ...manifest,\r\n files: {\r\n ...manifest.files,\r\n [filePath]: entry,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Check if manifest exists in a directory\r\n */\r\nexport async function hasManifest(projectDir: string): Promise<boolean> {\r\n const manifest = await readManifest(projectDir);\r\n return manifest !== null;\r\n}\r\n","// ============================================\r\n// Manifest Types for Incremental Generation\r\n// Public code - safe to distribute with CLI\r\n// ============================================\r\n\r\n/**\r\n * aerocoding-manifest.json entry for a single file\r\n */\r\nexport interface ManifestFileEntry {\r\n /** SHA-256 hash of file content */\r\n hash: string;\r\n /** File modification time in milliseconds */\r\n mtime: number;\r\n /** File size in bytes */\r\n size: number;\r\n /** Related entity ID (if applicable) */\r\n entityId?: string;\r\n /** File type for categorization */\r\n type?: 'entity' | 'usecase' | 'repository' | 'controller' | 'dto' | 'config' | 'test' | 'other';\r\n /** Bounded context name */\r\n contextName?: string;\r\n}\r\n\r\n/**\r\n * aerocoding-manifest.json structure\r\n * Tracks all generated files and their hashes\r\n */\r\nexport interface AeroManifest {\r\n /** Manifest format version */\r\n version: string;\r\n /** Last sync timestamp */\r\n lastSync: string;\r\n /** Template version at last generation */\r\n templateVersion: string;\r\n /** Map of file paths to their metadata */\r\n files: Record<string, ManifestFileEntry>;\r\n /** Entities that were generated */\r\n entities?: Array<{\r\n id: string;\r\n name: string;\r\n hash: string;\r\n contextName?: string;\r\n }>;\r\n}\r\n\r\n/**\r\n * Result of comparing a file with its manifest entry\r\n */\r\nexport type FileChangeStatus =\r\n | { status: 'new' }\r\n | { status: 'unchanged' }\r\n | { status: 'modified'; currentHash: string }\r\n | { status: 'deleted' }\r\n | { status: 'unknown' };\r\n\r\n// Constants\r\nexport const MANIFEST_VERSION = '1.0.0';\r\nexport const MANIFEST_FILENAME = 'aerocoding-manifest.json';\r\n","// ============================================\r\n// Hash Utilities for Incremental Generation\r\n// Public code - safe to distribute with CLI\r\n// ============================================\r\n\r\nimport * as crypto from 'crypto';\r\nimport * as fs from 'fs/promises';\r\nimport { createReadStream } from 'fs';\r\nimport type { ManifestFileEntry, FileChangeStatus } from './types.js';\r\n\r\n/**\r\n * Compute SHA-256 hash of a string\r\n */\r\nexport function hashString(content: string): string {\r\n return crypto.createHash('sha256').update(content, 'utf-8').digest('hex');\r\n}\r\n\r\n/**\r\n * Compute SHA-256 hash of a file using streaming (memory efficient)\r\n */\r\nexport async function hashFile(filePath: string): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const hash = crypto.createHash('sha256');\r\n const stream = createReadStream(filePath);\r\n\r\n stream.on('data', (chunk) => hash.update(chunk));\r\n stream.on('end', () => resolve(hash.digest('hex')));\r\n stream.on('error', reject);\r\n });\r\n}\r\n\r\n/**\r\n * Get file stats (mtime and size) for quick comparison\r\n */\r\nexport async function getFileStats(filePath: string): Promise<{ mtime: number; size: number } | null> {\r\n try {\r\n const stats = await fs.stat(filePath);\r\n return {\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Quick check if file might have changed based on mtime and size\r\n * Returns true if file MIGHT have changed (need hash verification)\r\n */\r\nexport function mightHaveChanged(\r\n currentStats: { mtime: number; size: number },\r\n manifestEntry: ManifestFileEntry\r\n): boolean {\r\n return currentStats.mtime !== manifestEntry.mtime || currentStats.size !== manifestEntry.size;\r\n}\r\n\r\n/**\r\n * Detect if a file has been modified by the user\r\n * Uses optimized two-phase check: mtime/size first, then hash if needed\r\n */\r\nexport async function detectFileChange(\r\n filePath: string,\r\n manifestEntry: ManifestFileEntry | undefined\r\n): Promise<FileChangeStatus> {\r\n const stats = await getFileStats(filePath);\r\n\r\n if (!stats) {\r\n if (manifestEntry) {\r\n return { status: 'deleted' };\r\n }\r\n return { status: 'new' };\r\n }\r\n\r\n if (!manifestEntry) {\r\n return { status: 'unknown' };\r\n }\r\n\r\n // Quick check with mtime/size\r\n if (!mightHaveChanged(stats, manifestEntry)) {\r\n return { status: 'unchanged' };\r\n }\r\n\r\n // Verify with hash\r\n const currentHash = await hashFile(filePath);\r\n\r\n if (currentHash === manifestEntry.hash) {\r\n return { status: 'unchanged' };\r\n }\r\n\r\n return { status: 'modified', currentHash };\r\n}\r\n","// ============================================\r\n// Three-Way Merge Implementation\r\n// ============================================\r\n\r\nimport diff3Merge from \"diff3\";\r\n\r\n/**\r\n * Result of a three-way merge operation\r\n */\r\nexport interface MergeResult {\r\n /** Whether the merge completed without conflicts */\r\n success: boolean;\r\n /** The merged content (may contain conflict markers if success=false) */\r\n content: string;\r\n /** Conflict regions if merge had conflicts */\r\n conflicts: ConflictRegion[];\r\n}\r\n\r\n/**\r\n * A region of conflict between user's changes and generated changes\r\n */\r\nexport interface ConflictRegion {\r\n /** Starting line number in the merged output */\r\n startLine: number;\r\n /** Ending line number in the merged output */\r\n endLine: number;\r\n /** User's version of the conflicting section */\r\n yours: string;\r\n /** Generated version of the conflicting section */\r\n generated: string;\r\n}\r\n\r\n/**\r\n * Perform a three-way merge between base, current (user's), and generated content.\r\n *\r\n * @param base - The original content (what was last generated/synced)\r\n * @param current - The current content on disk (may have user modifications)\r\n * @param generated - The newly generated content from the API\r\n * @returns MergeResult with success status, merged content, and any conflicts\r\n *\r\n * @example\r\n * ```typescript\r\n * const result = performMerge(\r\n * \"class Customer { }\", // base\r\n * \"class Customer { IsVip() }\", // current (user added method)\r\n * \"class Customer { Phone; }\" // generated (API added property)\r\n * );\r\n *\r\n * if (result.success) {\r\n * // Merged: class Customer { IsVip(); Phone; }\r\n * await writeFile(path, result.content);\r\n * } else {\r\n * // Has conflicts, need manual resolution\r\n * await writeConflictFiles(path, current, generated, result.conflicts);\r\n * }\r\n * ```\r\n */\r\nexport function performMerge(\r\n base: string,\r\n current: string,\r\n generated: string\r\n): MergeResult {\r\n // Split content into lines for diff3\r\n const baseLines = base.split(\"\\n\");\r\n const currentLines = current.split(\"\\n\");\r\n const generatedLines = generated.split(\"\\n\");\r\n\r\n // Perform three-way merge\r\n // diff3 returns array of regions: either string[] (clean) or { ok: string[] } or { conflict: { a, o, b } }\r\n const merged = diff3Merge(currentLines, baseLines, generatedLines);\r\n\r\n const conflicts: ConflictRegion[] = [];\r\n const outputLines: string[] = [];\r\n let lineNumber = 1;\r\n\r\n for (const region of merged) {\r\n if (Array.isArray(region)) {\r\n // Clean region - lines that merged without conflict\r\n outputLines.push(...region);\r\n lineNumber += region.length;\r\n } else if (\"ok\" in region && region.ok) {\r\n // OK region - also clean\r\n const okLines = region.ok;\r\n outputLines.push(...okLines);\r\n lineNumber += okLines.length;\r\n } else if (\"conflict\" in region && region.conflict) {\r\n // Conflict region\r\n const conflictData = region.conflict;\r\n const yoursLines = conflictData.a || [];\r\n const generatedLines = conflictData.b || [];\r\n const yours = yoursLines.join(\"\\n\");\r\n const generatedStr = generatedLines.join(\"\\n\");\r\n\r\n // Add conflict markers to output\r\n const conflictLines = [\r\n \"<<<<<<< YOURS\",\r\n ...yoursLines,\r\n \"=======\",\r\n ...generatedLines,\r\n \">>>>>>> GENERATED\",\r\n ];\r\n\r\n const startLine = lineNumber;\r\n outputLines.push(...conflictLines);\r\n lineNumber += conflictLines.length;\r\n\r\n conflicts.push({\r\n startLine,\r\n endLine: lineNumber - 1,\r\n yours,\r\n generated: generatedStr,\r\n });\r\n }\r\n }\r\n\r\n return {\r\n success: conflicts.length === 0,\r\n content: outputLines.join(\"\\n\"),\r\n conflicts,\r\n };\r\n}\r\n\r\n/**\r\n * Check if content has any conflict markers\r\n */\r\nexport function hasConflictMarkers(content: string): boolean {\r\n return (\r\n content.includes(\"<<<<<<< YOURS\") ||\r\n content.includes(\"=======\") ||\r\n content.includes(\">>>>>>> GENERATED\")\r\n );\r\n}\r\n\r\n/**\r\n * Extract clean content by removing conflict markers (for preview purposes)\r\n * Takes the \"YOURS\" side of each conflict\r\n */\r\nexport function extractYoursSide(content: string): string {\r\n const lines = content.split(\"\\n\");\r\n const output: string[] = [];\r\n let inConflict = false;\r\n let inGenerated = false;\r\n\r\n for (const line of lines) {\r\n if (line === \"<<<<<<< YOURS\") {\r\n inConflict = true;\r\n inGenerated = false;\r\n continue;\r\n }\r\n if (line === \"=======\") {\r\n inGenerated = true;\r\n continue;\r\n }\r\n if (line === \">>>>>>> GENERATED\") {\r\n inConflict = false;\r\n inGenerated = false;\r\n continue;\r\n }\r\n\r\n if (!inConflict || !inGenerated) {\r\n output.push(line);\r\n }\r\n }\r\n\r\n return output.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Extract clean content by removing conflict markers\r\n * Takes the \"GENERATED\" side of each conflict\r\n */\r\nexport function extractGeneratedSide(content: string): string {\r\n const lines = content.split(\"\\n\");\r\n const output: string[] = [];\r\n let inConflict = false;\r\n let inYours = false;\r\n\r\n for (const line of lines) {\r\n if (line === \"<<<<<<< YOURS\") {\r\n inConflict = true;\r\n inYours = true;\r\n continue;\r\n }\r\n if (line === \"=======\") {\r\n inYours = false;\r\n continue;\r\n }\r\n if (line === \">>>>>>> GENERATED\") {\r\n inConflict = false;\r\n continue;\r\n }\r\n\r\n if (!inConflict || !inYours) {\r\n output.push(line);\r\n }\r\n }\r\n\r\n return output.join(\"\\n\");\r\n}\r\n","// ============================================\r\n// Conflict File Writer\r\n// ============================================\r\n\r\nimport { writeFile, unlink, access } from \"node:fs/promises\";\r\nimport { basename, extname } from \"node:path\";\r\nimport type { ConflictRegion } from \"./merger.js\";\r\n\r\n/**\r\n * Extensions for conflict files\r\n */\r\nexport const CONFLICT_NEW_EXT = \".new\";\r\nexport const CONFLICT_DIFF_EXT = \".conflict\";\r\n\r\n/**\r\n * Write conflict files when merge fails\r\n *\r\n * Creates two files:\r\n * - `file.ext.new` - The newly generated version (complete)\r\n * - `file.ext.conflict` - A diff showing the conflicts with context\r\n *\r\n * The original file is left untouched.\r\n *\r\n * @param filePath - Path to the original file\r\n * @param generatedContent - The newly generated content\r\n * @param conflicts - The conflict regions from merge\r\n * @param currentContent - The current user content (for context in .conflict)\r\n */\r\nexport async function writeConflictFiles(\r\n filePath: string,\r\n generatedContent: string,\r\n conflicts: ConflictRegion[],\r\n currentContent: string\r\n): Promise<{ newPath: string; conflictPath: string }> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n // Write .new file with complete generated content\r\n await writeFile(newPath, generatedContent, \"utf-8\");\r\n\r\n // Write .conflict file with diff format\r\n const conflictContent = generateConflictFile(\r\n filePath,\r\n currentContent,\r\n generatedContent,\r\n conflicts\r\n );\r\n await writeFile(conflictPath, conflictContent, \"utf-8\");\r\n\r\n return { newPath, conflictPath };\r\n}\r\n\r\n/**\r\n * Generate the content of a .conflict file\r\n */\r\nfunction generateConflictFile(\r\n filePath: string,\r\n _currentContent: string,\r\n _generatedContent: string,\r\n conflicts: ConflictRegion[]\r\n): string {\r\n const fileName = basename(filePath);\r\n const ext = extname(filePath);\r\n const commentStyle = getCommentStyle(ext);\r\n\r\n const header = `${commentStyle.start}\r\n${commentStyle.prefix} ${fileName} - MERGE CONFLICT\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} This file has ${conflicts.length} conflict(s) that need manual resolution.\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} Resolution options:\r\n${commentStyle.prefix} 1. Edit ${fileName} to include both your changes and the generated changes\r\n${commentStyle.prefix} 2. Copy desired parts from ${fileName}${CONFLICT_NEW_EXT}\r\n${commentStyle.prefix} 3. Run 'aerocoding resolve' when done\r\n${commentStyle.prefix}\r\n${commentStyle.prefix} Your file: ${fileName} (unchanged)\r\n${commentStyle.prefix} Generated: ${fileName}${CONFLICT_NEW_EXT} (new version)\r\n${commentStyle.end}\r\n\r\n`;\r\n\r\n const conflictSections = conflicts\r\n .map((conflict, index) => {\r\n return `${commentStyle.start}\r\n${commentStyle.prefix} CONFLICT ${index + 1} of ${conflicts.length} (lines ${conflict.startLine}-${conflict.endLine})\r\n${commentStyle.end}\r\n\r\n<<<<<<< YOURS (keep your changes)\r\n${conflict.yours}\r\n=======\r\n${conflict.generated}\r\n>>>>>>> GENERATED (from template)\r\n`;\r\n })\r\n .join(\"\\n\");\r\n\r\n return header + conflictSections;\r\n}\r\n\r\n/**\r\n * Get comment style based on file extension\r\n */\r\nfunction getCommentStyle(ext: string): {\r\n start: string;\r\n prefix: string;\r\n end: string;\r\n} {\r\n switch (ext.toLowerCase()) {\r\n case \".cs\":\r\n case \".ts\":\r\n case \".tsx\":\r\n case \".js\":\r\n case \".jsx\":\r\n case \".java\":\r\n case \".kt\":\r\n case \".dart\":\r\n case \".go\":\r\n case \".swift\":\r\n case \".rs\":\r\n case \".c\":\r\n case \".cpp\":\r\n case \".h\":\r\n return { start: \"/*\", prefix: \" *\", end: \" */\" };\r\n\r\n case \".py\":\r\n case \".rb\":\r\n case \".sh\":\r\n case \".yaml\":\r\n case \".yml\":\r\n return { start: \"#\", prefix: \"#\", end: \"#\" };\r\n\r\n case \".html\":\r\n case \".xml\":\r\n case \".xaml\":\r\n case \".svg\":\r\n return { start: \"<!--\", prefix: \" \", end: \"-->\" };\r\n\r\n case \".sql\":\r\n return { start: \"--\", prefix: \"--\", end: \"--\" };\r\n\r\n case \".css\":\r\n case \".scss\":\r\n case \".less\":\r\n return { start: \"/*\", prefix: \" *\", end: \" */\" };\r\n\r\n default:\r\n return { start: \"//\", prefix: \"//\", end: \"//\" };\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file has pending conflict files\r\n */\r\nexport async function hasConflictFiles(filePath: string): Promise<boolean> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n try {\r\n await access(newPath);\r\n return true;\r\n } catch {\r\n // .new doesn't exist\r\n }\r\n\r\n try {\r\n await access(conflictPath);\r\n return true;\r\n } catch {\r\n // .conflict doesn't exist\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Remove conflict files after resolution\r\n */\r\nexport async function removeConflictFiles(\r\n filePath: string\r\n): Promise<{ removedNew: boolean; removedConflict: boolean }> {\r\n const newPath = `${filePath}${CONFLICT_NEW_EXT}`;\r\n const conflictPath = `${filePath}${CONFLICT_DIFF_EXT}`;\r\n\r\n let removedNew = false;\r\n let removedConflict = false;\r\n\r\n try {\r\n await unlink(newPath);\r\n removedNew = true;\r\n } catch {\r\n // File didn't exist, that's fine\r\n }\r\n\r\n try {\r\n await unlink(conflictPath);\r\n removedConflict = true;\r\n } catch {\r\n // File didn't exist, that's fine\r\n }\r\n\r\n return { removedNew, removedConflict };\r\n}\r\n\r\n/**\r\n * Find all conflict files in a directory\r\n */\r\nexport function getConflictFilePaths(originalPath: string): {\r\n newPath: string;\r\n conflictPath: string;\r\n} {\r\n return {\r\n newPath: `${originalPath}${CONFLICT_NEW_EXT}`,\r\n conflictPath: `${originalPath}${CONFLICT_DIFF_EXT}`,\r\n };\r\n}\r\n","import { z } from \"zod\";\r\nimport { readFile, writeFile, access } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\n\r\n// ============================================\r\n// aerocoding.json - Project Configuration\r\n// New format for incremental generation\r\n// ============================================\r\n\r\nexport const PROJECT_CONFIG_FILENAME = \"aerocoding.json\";\r\n\r\n/**\r\n * Schema for aerocoding.json\r\n * This is the user-editable config for the meta-framework approach\r\n */\r\nexport const projectConfigSchema = z.object({\r\n $schema: z.string().optional().default(\"https://aerocoding.dev/schema.json\"),\r\n\r\n /** Project UUID from aerocoding.dev */\r\n projectId: z.string().uuid(),\r\n\r\n /** Template ID for architecture generation */\r\n templateId: z.string().min(1),\r\n\r\n /** Template version at project creation */\r\n templateVersion: z.string().optional(),\r\n\r\n /** Root namespace/package name */\r\n namespace: z.string().min(1),\r\n\r\n /** Output directories */\r\n output: z.object({\r\n backend: z.string().default(\"./backend\"),\r\n frontend: z.string().default(\"./frontend\"),\r\n }).optional().default({ backend: \"./backend\", frontend: \"./frontend\" }),\r\n\r\n /** Organization ID (for cloud sync) */\r\n organizationId: z.string().uuid().optional(),\r\n});\r\n\r\nexport type ProjectConfig = z.infer<typeof projectConfigSchema>;\r\n\r\n/**\r\n * Check if aerocoding.json exists in a directory\r\n */\r\nexport async function projectConfigExists(dir: string = process.cwd()): Promise<boolean> {\r\n try {\r\n await access(join(dir, PROJECT_CONFIG_FILENAME));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Load aerocoding.json from a directory\r\n */\r\nexport async function loadProjectConfig(dir: string = process.cwd()): Promise<ProjectConfig | null> {\r\n try {\r\n const configPath = join(dir, PROJECT_CONFIG_FILENAME);\r\n const content = await readFile(configPath, \"utf-8\");\r\n const parsed = JSON.parse(content);\r\n return projectConfigSchema.parse(parsed);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Save aerocoding.json to a directory\r\n */\r\nexport async function saveProjectConfig(config: ProjectConfig, dir: string = process.cwd()): Promise<void> {\r\n const configPath = join(dir, PROJECT_CONFIG_FILENAME);\r\n const content = JSON.stringify(config, null, 2);\r\n await writeFile(configPath, content, \"utf-8\");\r\n}\r\n\r\n/**\r\n * Create a new project config\r\n */\r\nexport function createProjectConfig(options: {\r\n projectId: string;\r\n templateId: string;\r\n templateVersion?: string;\r\n namespace: string;\r\n organizationId?: string;\r\n output?: { backend?: string; frontend?: string };\r\n}): ProjectConfig {\r\n return {\r\n $schema: \"https://aerocoding.dev/schema.json\",\r\n projectId: options.projectId,\r\n templateId: options.templateId,\r\n templateVersion: options.templateVersion,\r\n namespace: options.namespace,\r\n organizationId: options.organizationId,\r\n output: {\r\n backend: options.output?.backend || \"./backend\",\r\n frontend: options.output?.frontend || \"./frontend\",\r\n },\r\n };\r\n}\r\n","// ============================================\r\n// Cloud Sync - Manifest Backup/Recovery\r\n// ============================================\r\n\r\nimport { ApiClient, CloudManifest } from \"../api/client.js\";\r\nimport type { AeroManifest } from \"../manifest/types.js\";\r\n\r\n/**\r\n * Convert local manifest to cloud format\r\n * Strips entities array (not needed for cloud backup)\r\n */\r\nexport function toCloudManifest(manifest: AeroManifest): CloudManifest {\r\n return {\r\n version: manifest.version,\r\n lastSync: manifest.lastSync,\r\n templateVersion: manifest.templateVersion,\r\n files: manifest.files,\r\n };\r\n}\r\n\r\n/**\r\n * Convert cloud manifest back to local format\r\n */\r\nexport function fromCloudManifest(\r\n cloudManifest: CloudManifest,\r\n templateVersion: string\r\n): AeroManifest {\r\n return {\r\n version: cloudManifest.version,\r\n lastSync: cloudManifest.lastSync || new Date().toISOString(),\r\n templateVersion: cloudManifest.templateVersion || templateVersion,\r\n files: cloudManifest.files,\r\n entities: [], // Will be rebuilt on next generation\r\n };\r\n}\r\n\r\n/**\r\n * Sync local manifest to cloud\r\n *\r\n * @returns Success status and file count\r\n */\r\nexport async function syncToCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n manifest: AeroManifest\r\n): Promise<{ success: boolean; fileCount: number }> {\r\n const cloudManifest = toCloudManifest(manifest);\r\n const result = await apiClient.saveManifest(projectId, cloudManifest);\r\n\r\n return {\r\n success: result.success,\r\n fileCount: result.fileCount,\r\n };\r\n}\r\n\r\n/**\r\n * Fetch manifest from cloud\r\n *\r\n * @returns Manifest or null if not found\r\n */\r\nexport async function fetchFromCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n templateVersion: string\r\n): Promise<AeroManifest | null> {\r\n const cloudManifest = await apiClient.getManifest(projectId);\r\n\r\n if (!cloudManifest) {\r\n return null;\r\n }\r\n\r\n return fromCloudManifest(cloudManifest, templateVersion);\r\n}\r\n\r\n/**\r\n * Check if cloud has a more recent manifest\r\n *\r\n * @returns Object with comparison info\r\n */\r\nexport async function compareWithCloud(\r\n apiClient: ApiClient,\r\n projectId: string,\r\n localManifest: AeroManifest | null\r\n): Promise<{\r\n hasCloudBackup: boolean;\r\n cloudLastSync: string | null;\r\n localLastSync: string | null;\r\n isCloudNewer: boolean;\r\n cloudFileCount: number;\r\n localFileCount: number;\r\n}> {\r\n const cloudManifest = await apiClient.getManifest(projectId);\r\n\r\n const cloudLastSync = cloudManifest?.lastSync || null;\r\n const localLastSync = localManifest?.lastSync || null;\r\n const cloudFileCount = cloudManifest ? Object.keys(cloudManifest.files).length : 0;\r\n const localFileCount = localManifest ? Object.keys(localManifest.files).length : 0;\r\n\r\n // Determine if cloud is newer\r\n let isCloudNewer = false;\r\n if (cloudLastSync && localLastSync) {\r\n isCloudNewer = new Date(cloudLastSync) > new Date(localLastSync);\r\n } else if (cloudLastSync && !localLastSync) {\r\n isCloudNewer = true;\r\n }\r\n\r\n return {\r\n hasCloudBackup: cloudManifest !== null,\r\n cloudLastSync,\r\n localLastSync,\r\n isCloudNewer,\r\n cloudFileCount,\r\n localFileCount,\r\n };\r\n}\r\n\r\n/**\r\n * Format a date for display\r\n */\r\nexport function formatSyncDate(isoDate: string | null): string {\r\n if (!isoDate) return \"never\";\r\n\r\n const date = new Date(isoDate);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return \"just now\";\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n\r\n return date.toLocaleDateString();\r\n}\r\n","// ============================================\r\n// Update Command - Incremental Code Generation\r\n// ============================================\r\n\r\nimport * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport ora from \"ora\";\r\nimport { TokenManager } from \"../auth/token-manager.js\";\r\nimport { createApiClientWithAutoLogout } from \"./_shared/create-api-client.js\";\r\nimport { handleUnauthorized } from \"./_shared/unauthorized.js\";\r\nimport { writeGeneratedFilesWithManifest } from \"../utils/file-writer.js\";\r\nimport { loadProjectConfig, PROJECT_CONFIG_FILENAME } from \"../config/project-config.js\";\r\nimport { readManifest, writeManifest } from \"../manifest/index.js\";\r\nimport {\r\n syncToCloud,\r\n fetchFromCloud,\r\n compareWithCloud,\r\n formatSyncDate,\r\n} from \"../utils/cloud-sync.js\";\r\n\r\ninterface UpdateOptions {\r\n force?: boolean;\r\n verbose?: boolean;\r\n dryRun?: boolean;\r\n}\r\n\r\n/**\r\n * Update Command\r\n *\r\n * Incrementally updates generated code by:\r\n * 1. Reading aerocoding.json config\r\n * 2. Fetching latest schema from aerocoding.dev\r\n * 3. Regenerating code with current template\r\n * 4. Using three-way merge to preserve user changes\r\n * 5. Creating .new/.conflict files for manual resolution\r\n *\r\n * @ai-critical Core command for incremental generation workflow\r\n */\r\nexport async function updateCommand(options: UpdateOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Update \"));\r\n\r\n // 1. Load project config\r\n const config = await loadProjectConfig();\r\n\r\n if (!config) {\r\n p.cancel(\r\n `No ${PROJECT_CONFIG_FILENAME} found. Run 'aerocoding create' first.`\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // 2. Check authentication\r\n const tokenManager = new TokenManager();\r\n const token = await tokenManager.getAccessToken();\r\n\r\n if (!token) {\r\n p.cancel(\"Not logged in. Run 'aerocoding login' first.\");\r\n process.exit(1);\r\n }\r\n\r\n const apiClient = createApiClientWithAutoLogout(token, tokenManager);\r\n\r\n try {\r\n // 3. Load existing manifest (if any)\r\n let manifest = await readManifest(process.cwd());\r\n let fileCount = manifest ? Object.keys(manifest.files).length : 0;\r\n\r\n if (manifest) {\r\n p.log.info(\r\n `Found manifest with ${fileCount} tracked files (last sync: ${manifest.lastSync || \"unknown\"})`\r\n );\r\n } else {\r\n // No local manifest - check cloud for backup\r\n p.log.warn(\"No local manifest found.\");\r\n\r\n const cloudCheck = await compareWithCloud(apiClient, config.projectId, null);\r\n\r\n if (cloudCheck.hasCloudBackup) {\r\n p.log.info(\r\n chalk.cyan(\r\n ` Cloud backup available (${cloudCheck.cloudFileCount} files, synced ${formatSyncDate(cloudCheck.cloudLastSync)})`\r\n )\r\n );\r\n\r\n const recovery = await p.select({\r\n message: \"How would you like to proceed?\",\r\n options: [\r\n {\r\n value: \"restore\",\r\n label: \"Restore from cloud backup\",\r\n hint: \"recommended\",\r\n },\r\n {\r\n value: \"continue\",\r\n label: \"Continue anyway\",\r\n hint: \"all files will be treated as new\",\r\n },\r\n { value: \"cancel\", label: \"Cancel\" },\r\n ],\r\n });\r\n\r\n if (p.isCancel(recovery) || recovery === \"cancel\") {\r\n p.cancel(\"Update cancelled.\");\r\n process.exit(0);\r\n }\r\n\r\n if (recovery === \"restore\") {\r\n const restoreSpinner = p.spinner();\r\n restoreSpinner.start(\"Restoring manifest from cloud...\");\r\n\r\n const cloudManifest = await fetchFromCloud(\r\n apiClient,\r\n config.projectId,\r\n config.templateVersion || \"1.0.0\"\r\n );\r\n\r\n if (cloudManifest) {\r\n await writeManifest(process.cwd(), cloudManifest);\r\n manifest = cloudManifest;\r\n fileCount = Object.keys(manifest.files).length;\r\n restoreSpinner.stop(\r\n chalk.green(`Restored ${fileCount} files from cloud backup`)\r\n );\r\n } else {\r\n restoreSpinner.stop(chalk.yellow(\"Cloud backup not found\"));\r\n }\r\n }\r\n } else {\r\n p.log.info(\r\n chalk.gray(\" No cloud backup available. All generated files will be created as new.\")\r\n );\r\n }\r\n }\r\n\r\n // 4. Fetch project details\r\n const projectSpinner = p.spinner();\r\n projectSpinner.start(\"Fetching project details...\");\r\n const project = await apiClient.getProject(config.projectId);\r\n projectSpinner.stop(`Project: ${project.name}`);\r\n\r\n // 5. Show update summary\r\n p.log.step(chalk.bold(\"Update Configuration:\"));\r\n p.log.info(` Project: ${project.name}`);\r\n p.log.info(` Template: ${config.templateId}`);\r\n p.log.info(` Namespace: ${config.namespace}`);\r\n p.log.info(` Output: ${config.output.backend}`);\r\n\r\n if (options.dryRun) {\r\n p.log.info(chalk.yellow(\" Mode: DRY RUN (no files will be written)\"));\r\n }\r\n if (options.force) {\r\n p.log.info(chalk.yellow(\" Mode: FORCE (will overwrite modified files)\"));\r\n }\r\n\r\n // 6. Get credit estimate BEFORE confirmation\r\n let estimatedCredits = 0;\r\n let creditsRemaining = 0;\r\n\r\n const estimateSpinner = p.spinner();\r\n estimateSpinner.start(\"Calculating credit cost...\");\r\n\r\n try {\r\n const estimate = await apiClient.estimateCreditCost({\r\n projectId: config.projectId,\r\n templateId: config.templateId,\r\n options: {\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: false,\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n estimatedCredits = estimate.estimatedCredits;\r\n\r\n // Get remaining credits\r\n const creditUsage = await apiClient.getCreditUsage(project.organizationId);\r\n creditsRemaining = creditUsage.remaining;\r\n\r\n estimateSpinner.stop(\"Credit estimate calculated\");\r\n } catch {\r\n estimateSpinner.stop(\"Could not estimate credits (will be calculated on generation)\");\r\n }\r\n\r\n if (estimatedCredits > 0) {\r\n console.log(\"\");\r\n p.log.info(chalk.yellow(` Estimated Credits: ~${estimatedCredits}`));\r\n p.log.info(chalk.gray(` Your Balance: ${creditsRemaining}`));\r\n\r\n if (creditsRemaining < estimatedCredits) {\r\n p.log.warn(chalk.red(\" ⚠ You may not have enough credits for this generation.\"));\r\n }\r\n }\r\n\r\n // 7. Confirm update\r\n if (!options.dryRun) {\r\n const proceed = await p.confirm({\r\n message: estimatedCredits > 0\r\n ? `Proceed with update (~${estimatedCredits} credits)?`\r\n : \"Proceed with update?\",\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Update cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n\r\n // 7. Generate code\r\n const genSpinner = ora({\r\n text: \"Generating code from latest schema...\",\r\n color: \"cyan\",\r\n }).start();\r\n\r\n const result = await apiClient.generateCode({\r\n projectId: config.projectId,\r\n templateId: config.templateId,\r\n options: {\r\n includeValidations: true,\r\n includeComments: true,\r\n featureFlags: {\r\n includeDtos: true,\r\n includeUseCases: true,\r\n includeMappers: true,\r\n includeControllers: true,\r\n includeEfConfig: true,\r\n includeValidation: true,\r\n includeDtoValidation: true,\r\n includeUnitTests: true,\r\n includeIntegrationTests: true,\r\n includeStarterFiles: false, // Don't regenerate starter files\r\n },\r\n useContexts: true,\r\n },\r\n });\r\n\r\n genSpinner.succeed(\r\n chalk.green(`Generated ${result.files?.length || 0} files from schema`)\r\n );\r\n\r\n if (options.dryRun) {\r\n // Dry run - just show what would happen\r\n p.log.info(\"\");\r\n p.log.info(chalk.bold(\" Dry Run Results:\"));\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n p.log.info(` Files to process: ${result.files?.length || 0}`);\r\n p.log.info(` Tracked files: ${fileCount}`);\r\n p.log.info(\"\");\r\n p.log.info(chalk.gray(\" Run without --dry-run to apply changes.\"));\r\n\r\n p.outro(chalk.green(\"Dry run complete!\"));\r\n return;\r\n }\r\n\r\n // 8. Apply updates with merge\r\n const updateSpinner = p.spinner();\r\n updateSpinner.start(\"Applying updates...\");\r\n\r\n // Organize files into backend folder (matching create command structure)\r\n const organizedFiles = result.files.map(\r\n (file: { path: string; content: string; language: string }) => ({\r\n ...file,\r\n path: `${config.output.backend.replace(/^\\.\\//, \"\")}/${file.path}`,\r\n })\r\n );\r\n\r\n const writeResult = await writeGeneratedFilesWithManifest(\r\n organizedFiles,\r\n process.cwd(),\r\n config.templateVersion || \"1.0.0\",\r\n {\r\n verbose: options.verbose,\r\n forceOverwrite: options.force,\r\n }\r\n );\r\n\r\n updateSpinner.stop(\"Update complete\");\r\n\r\n // 9. Show credits\r\n if (result.creditsUsed !== undefined) {\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Credits used:\"), chalk.yellow(result.creditsUsed));\r\n console.log(\r\n chalk.gray(\" Credits remaining:\"),\r\n chalk.green(result.creditsRemaining)\r\n );\r\n }\r\n\r\n // 10. Sync manifest to cloud\r\n try {\r\n const syncResult = await syncToCloud(\r\n apiClient,\r\n config.projectId,\r\n writeResult.manifest\r\n );\r\n if (syncResult.success) {\r\n console.log(\r\n chalk.gray(\" ✓ Manifest synced to cloud\") +\r\n chalk.gray(` (${syncResult.fileCount} files)`)\r\n );\r\n }\r\n } catch (syncError) {\r\n // Non-fatal - just log warning\r\n console.log(chalk.yellow(\" ⚠ Could not sync manifest to cloud\"));\r\n if (options.verbose) {\r\n console.log(chalk.gray(` ${(syncError as Error).message}`));\r\n }\r\n }\r\n\r\n // 11. Show final message\r\n if (writeResult.conflicts.length > 0) {\r\n p.outro(\r\n chalk.yellow(`Update complete with ${writeResult.conflicts.length} conflict(s).`) +\r\n \"\\n\" +\r\n chalk.gray(\" Run 'aerocoding resolve' after fixing conflicts.\")\r\n );\r\n } else {\r\n const totalWritten =\r\n writeResult.created.length +\r\n writeResult.updated.length +\r\n writeResult.merged.length;\r\n\r\n p.outro(\r\n chalk.green(`Update complete! ${totalWritten} file(s) written.`)\r\n );\r\n }\r\n } catch (error: unknown) {\r\n const err = error as {\r\n response?: { status?: number; data?: { message?: string } };\r\n message?: string;\r\n };\r\n if (err.response?.status === 401) {\r\n await handleUnauthorized(tokenManager);\r\n } else if (err.response?.data?.message) {\r\n p.cancel(err.response.data.message);\r\n } else {\r\n p.cancel(err.message || \"An unexpected error occurred\");\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n","// ============================================\r\n// Resolve Command - Clean up merge conflicts\r\n// ============================================\r\n\r\nimport * as p from \"@clack/prompts\";\r\nimport chalk from \"chalk\";\r\nimport { readdir, stat } from \"node:fs/promises\";\r\nimport { join, relative } from \"node:path\";\r\nimport {\r\n removeConflictFiles,\r\n CONFLICT_NEW_EXT,\r\n CONFLICT_DIFF_EXT,\r\n} from \"../merge/index.js\";\r\nimport {\r\n readManifest,\r\n writeManifest,\r\n setManifestFile,\r\n hashFile,\r\n} from \"../manifest/index.js\";\r\nimport { loadProjectConfig, PROJECT_CONFIG_FILENAME } from \"../config/project-config.js\";\r\n\r\ninterface ResolveOptions {\r\n verbose?: boolean;\r\n all?: boolean;\r\n}\r\n\r\ninterface ConflictFile {\r\n originalPath: string;\r\n newPath: string;\r\n conflictPath: string;\r\n}\r\n\r\n/**\r\n * Resolve Command\r\n *\r\n * Cleans up conflict files after user has manually resolved merge conflicts.\r\n *\r\n * Flow:\r\n * 1. Find all .new and .conflict files\r\n * 2. For each conflict:\r\n * - Verify original file exists (user resolved it)\r\n * - Remove .new and .conflict files\r\n * - Update manifest with new hash\r\n *\r\n * @ai-critical Part of incremental generation workflow\r\n */\r\nexport async function resolveCommand(options: ResolveOptions) {\r\n p.intro(chalk.bgCyan.black(\" AeroCoding Resolve \"));\r\n\r\n // 1. Load project config\r\n const config = await loadProjectConfig();\r\n\r\n if (!config) {\r\n p.cancel(\r\n `No ${PROJECT_CONFIG_FILENAME} found. Run 'aerocoding create' first.`\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // 2. Find all conflict files\r\n const spinner = p.spinner();\r\n spinner.start(\"Scanning for conflict files...\");\r\n\r\n const conflicts = await findConflictFiles(process.cwd());\r\n spinner.stop(`Found ${conflicts.length} conflict(s)`);\r\n\r\n if (conflicts.length === 0) {\r\n p.log.success(\"No conflicts to resolve!\");\r\n p.outro(chalk.green(\"All clear!\"));\r\n return;\r\n }\r\n\r\n // 3. Show conflicts\r\n p.log.info(\"\");\r\n p.log.info(chalk.bold(\" Pending Conflicts:\"));\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n for (const conflict of conflicts) {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n p.log.info(chalk.yellow(` ⚠ ${relPath}`));\r\n if (options.verbose) {\r\n p.log.info(chalk.gray(` → ${relative(process.cwd(), conflict.newPath)}`));\r\n p.log.info(\r\n chalk.gray(` → ${relative(process.cwd(), conflict.conflictPath)}`)\r\n );\r\n }\r\n }\r\n\r\n p.log.info(chalk.gray(\" ─────────────────────────────────\"));\r\n p.log.info(\"\");\r\n\r\n // 4. Confirm resolution\r\n if (!options.all) {\r\n const proceed = await p.confirm({\r\n message: `Remove ${conflicts.length} conflict file(s)? (This assumes you've resolved them)`,\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(proceed) || !proceed) {\r\n p.cancel(\"Resolution cancelled.\");\r\n process.exit(0);\r\n }\r\n }\r\n\r\n // 5. Load manifest\r\n let manifest = await readManifest(process.cwd());\r\n\r\n if (!manifest) {\r\n p.cancel(\"No manifest found. Cannot update file hashes.\");\r\n process.exit(1);\r\n }\r\n\r\n // 6. Resolve each conflict\r\n const resolveSpinner = p.spinner();\r\n resolveSpinner.start(\"Resolving conflicts...\");\r\n\r\n let resolved = 0;\r\n let failed = 0;\r\n\r\n for (const conflict of conflicts) {\r\n try {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n\r\n // Verify original file exists\r\n try {\r\n await stat(conflict.originalPath);\r\n } catch {\r\n if (options.verbose) {\r\n console.log(\r\n chalk.red(` ✗ ${relPath} - original file not found`)\r\n );\r\n }\r\n failed++;\r\n continue;\r\n }\r\n\r\n // Remove conflict files\r\n const { removedNew, removedConflict } = await removeConflictFiles(\r\n conflict.originalPath\r\n );\r\n\r\n // Update manifest with new hash\r\n const newHash = await hashFile(conflict.originalPath);\r\n const stats = await stat(conflict.originalPath);\r\n\r\n // Get path relative to project root for manifest\r\n const manifestPath = relPath.replace(/\\\\/g, \"/\");\r\n const existingEntry = manifest.files[manifestPath];\r\n\r\n manifest = setManifestFile(manifest, manifestPath, {\r\n hash: newHash,\r\n mtime: Math.floor(stats.mtimeMs),\r\n size: stats.size,\r\n entityId: existingEntry?.entityId,\r\n type: existingEntry?.type || \"other\",\r\n contextName: existingEntry?.contextName,\r\n });\r\n\r\n if (options.verbose) {\r\n const removed = [];\r\n if (removedNew) removed.push(\".new\");\r\n if (removedConflict) removed.push(\".conflict\");\r\n console.log(\r\n chalk.green(` ✓ ${relPath}`) +\r\n chalk.gray(` (removed ${removed.join(\", \")})`)\r\n );\r\n }\r\n\r\n resolved++;\r\n } catch (error) {\r\n failed++;\r\n if (options.verbose) {\r\n const relPath = relative(process.cwd(), conflict.originalPath);\r\n console.log(chalk.red(` ✗ ${relPath} - ${error}`));\r\n }\r\n }\r\n }\r\n\r\n // 7. Save updated manifest\r\n manifest = {\r\n ...manifest,\r\n lastSync: new Date().toISOString(),\r\n };\r\n\r\n await writeManifest(process.cwd(), manifest);\r\n resolveSpinner.stop(\"Conflicts resolved\");\r\n\r\n // 8. Show results\r\n console.log(\"\");\r\n console.log(chalk.bold(\" Resolution Results\"));\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (resolved > 0) {\r\n console.log(chalk.green(` ✓ Resolved: ${resolved} files`));\r\n }\r\n if (failed > 0) {\r\n console.log(chalk.red(` ✗ Failed: ${failed} files`));\r\n }\r\n\r\n console.log(chalk.gray(\" ─────────────────────────────────\"));\r\n\r\n if (failed > 0) {\r\n p.outro(\r\n chalk.yellow(\r\n `Resolved ${resolved} conflict(s), ${failed} failed.`\r\n )\r\n );\r\n } else {\r\n p.outro(chalk.green(`All ${resolved} conflict(s) resolved!`));\r\n }\r\n}\r\n\r\n/**\r\n * Recursively find all conflict files in a directory\r\n */\r\nasync function findConflictFiles(dir: string): Promise<ConflictFile[]> {\r\n const conflicts: ConflictFile[] = [];\r\n\r\n async function scan(currentDir: string) {\r\n try {\r\n const entries = await readdir(currentDir, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const fullPath = join(currentDir, entry.name);\r\n\r\n // Skip node_modules and hidden directories\r\n if (entry.isDirectory()) {\r\n if (\r\n entry.name === \"node_modules\" ||\r\n entry.name === \".git\" ||\r\n entry.name.startsWith(\".\")\r\n ) {\r\n continue;\r\n }\r\n await scan(fullPath);\r\n } else if (entry.isFile()) {\r\n // Check for .new files\r\n if (entry.name.endsWith(CONFLICT_NEW_EXT)) {\r\n const originalPath = fullPath.slice(\r\n 0,\r\n -CONFLICT_NEW_EXT.length\r\n );\r\n const conflictPath = originalPath + CONFLICT_DIFF_EXT;\r\n\r\n // Only add if we haven't already found this conflict\r\n const existing = conflicts.find(\r\n (c) => c.originalPath === originalPath\r\n );\r\n if (!existing) {\r\n conflicts.push({\r\n originalPath,\r\n newPath: fullPath,\r\n conflictPath,\r\n });\r\n }\r\n }\r\n // Check for .conflict files (in case .new was deleted)\r\n else if (entry.name.endsWith(CONFLICT_DIFF_EXT)) {\r\n const originalPath = fullPath.slice(\r\n 0,\r\n -CONFLICT_DIFF_EXT.length\r\n );\r\n const newPath = originalPath + CONFLICT_NEW_EXT;\r\n\r\n // Only add if we haven't already found this conflict\r\n const existing = conflicts.find(\r\n (c) => c.originalPath === originalPath\r\n );\r\n if (!existing) {\r\n conflicts.push({\r\n originalPath,\r\n newPath,\r\n conflictPath: fullPath,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n } catch {\r\n // Ignore directories we can't read\r\n }\r\n }\r\n\r\n await scan(dir);\r\n return conflicts;\r\n}\r\n"],"mappings":"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","names":["chalk","spinner","resolve","axios","API_URL","chalk","chalk","chalk","chalk","chalk","chalk","chalk","ora","access","fs","path","chalk","fs","resolve","generatedLines","writeFile","path","chalk","fs","readFile","writeFile","access","join","join","readFile","writeFile","chalk","spinner","access","ora","p","chalk","ora","chalk","ora","p","chalk","stat","join","chalk","spinner","stat","join"]}
|