@bluealba/platform-cli 0.3.1-feature-add-new-commands-226 → 0.3.1-feature-platform-cli-228

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -311,7 +311,12 @@ async function scaffoldBootstrap(bootstrapServiceDir, organizationName, bootstra
311
311
  {
312
312
  templateDir: bootstrapTemplateDir,
313
313
  outputDir: bootstrapServiceDir,
314
- variables: { organizationName, bootstrapName, bootstrapServiceDir: bootstrapServiceDir_var },
314
+ variables: {
315
+ organizationName,
316
+ bootstrapName,
317
+ bootstrapServiceName: `${bootstrapName}-bootstrap-service`,
318
+ bootstrapServiceDir: bootstrapServiceDir_var
319
+ },
315
320
  exclude: ["src/data/shared-libraries.json", "src/data/platform/modules-config.json"]
316
321
  },
317
322
  (message) => logger.log(message)
@@ -628,7 +633,8 @@ function addApplicationToManifest(manifest, app) {
628
633
  var CREATE_APPLICATION_COMMAND_NAME = "create-application";
629
634
  var createApplicationCommand = {
630
635
  name: CREATE_APPLICATION_COMMAND_NAME,
631
- description: "Create an application in a platform"
636
+ description: "Create an application in a platform",
637
+ hidden: (ctx) => !ctx.platformInitialized
632
638
  };
633
639
  async function createApplication(params, logger) {
634
640
  const {
@@ -871,6 +877,8 @@ async function init(params, logger) {
871
877
  platformTitle,
872
878
  platformDisplayName,
873
879
  bootstrapName: platformName,
880
+ bootstrapServiceName,
881
+ customizationUiName,
874
882
  bootstrapServiceDir: `${coreDirName}/services`
875
883
  };
876
884
  try {
@@ -1003,7 +1011,8 @@ function getAllProviders() {
1003
1011
  var CONFIGURE_IDP_COMMAND_NAME = "configure-idp";
1004
1012
  var configureIdpCommand = {
1005
1013
  name: CONFIGURE_IDP_COMMAND_NAME,
1006
- description: "Configure an Identity Provider (IDP) in the gateway"
1014
+ description: "Configure an Identity Provider (IDP) in the gateway",
1015
+ hidden: (ctx) => !ctx.platformInitialized
1007
1016
  };
1008
1017
  async function configureIdp(params, logger) {
1009
1018
  const layout = await findPlatformLayout();
@@ -1134,7 +1143,8 @@ async function appendServiceToDockerCompose(dockerComposePath, serviceName, plat
1134
1143
  var CREATE_SERVICE_MODULE_COMMAND_NAME = "create-service-module";
1135
1144
  var createServiceModuleCommand = {
1136
1145
  name: CREATE_SERVICE_MODULE_COMMAND_NAME,
1137
- description: "Add a new service module to an existing application"
1146
+ description: "Add a new service module to an existing application",
1147
+ hidden: (ctx) => !ctx.platformInitialized
1138
1148
  };
1139
1149
  async function createServiceModule(params, logger) {
1140
1150
  const { applicationName, serviceName, serviceDisplayName, serviceNameSuffix } = params;
@@ -1228,7 +1238,8 @@ async function appendUiToDockerCompose(dockerComposePath, platformName, applicat
1228
1238
  var CREATE_UI_MODULE_COMMAND_NAME = "create-ui-module";
1229
1239
  var createUiModuleCommand = {
1230
1240
  name: CREATE_UI_MODULE_COMMAND_NAME,
1231
- description: "Add a UI module to an existing application"
1241
+ description: "Add a UI module to an existing application",
1242
+ hidden: (ctx) => !ctx.platformInitialized
1232
1243
  };
1233
1244
  async function createUiModule(params, logger) {
1234
1245
  const { applicationName, applicationDisplayName, uiModuleSuffix } = params;
@@ -1287,13 +1298,274 @@ async function createUiModule(params, logger) {
1287
1298
  logger.log(`Done! UI module "${uiName}" added to application "${applicationName}".`);
1288
1299
  }
1289
1300
 
1290
- // src/commands/local-scripts/docker-compose-orchestrator.ts
1301
+ // src/commands/status/status-checks.ts
1291
1302
  import { spawn } from "child_process";
1292
1303
  import { access as access5 } from "fs/promises";
1293
- import { join as join22 } from "path";
1304
+ import { join as join22, resolve as resolve4 } from "path";
1305
+ function spawnCapture(cmd, args2, cwd5) {
1306
+ return new Promise((resolvePromise) => {
1307
+ const child = spawn(cmd, args2, {
1308
+ cwd: cwd5,
1309
+ shell: false,
1310
+ stdio: ["ignore", "pipe", "pipe"]
1311
+ });
1312
+ let stdout = "";
1313
+ let stderr = "";
1314
+ child.stdout.on("data", (data) => {
1315
+ stdout += data.toString();
1316
+ });
1317
+ child.stderr.on("data", (data) => {
1318
+ stderr += data.toString();
1319
+ });
1320
+ child.on("close", (code) => {
1321
+ resolvePromise({ code: code ?? 1, stdout, stderr });
1322
+ });
1323
+ child.on("error", () => {
1324
+ resolvePromise({ code: 1, stdout, stderr });
1325
+ });
1326
+ });
1327
+ }
1328
+ async function pathExists(p) {
1329
+ try {
1330
+ await access5(p);
1331
+ return true;
1332
+ } catch {
1333
+ return false;
1334
+ }
1335
+ }
1336
+ async function checkNodeVersion() {
1337
+ const { code, stdout } = await spawnCapture("node", ["--version"]);
1338
+ if (code !== 0 || !stdout.trim()) {
1339
+ return { name: "Node.js", available: false, version: null, versionOk: false, detail: "not found in PATH" };
1340
+ }
1341
+ const version2 = stdout.trim();
1342
+ const match = version2.match(/^v(\d+)/);
1343
+ const major = match ? parseInt(match[1], 10) : 0;
1344
+ const versionOk = major >= 22;
1345
+ return {
1346
+ name: "Node.js",
1347
+ available: true,
1348
+ version: version2,
1349
+ versionOk,
1350
+ detail: versionOk ? void 0 : `>=22 required, found ${version2}`
1351
+ };
1352
+ }
1353
+ async function checkDocker() {
1354
+ const { code, stdout } = await spawnCapture("docker", ["info", "--format", "{{.ServerVersion}}"]);
1355
+ if (code === 0 && stdout.trim()) {
1356
+ return { name: "Docker", available: true, version: stdout.trim(), versionOk: true };
1357
+ }
1358
+ const { code: vCode, stdout: vOut } = await spawnCapture("docker", ["--version"]);
1359
+ if (vCode === 0 && vOut.trim()) {
1360
+ return {
1361
+ name: "Docker",
1362
+ available: false,
1363
+ version: null,
1364
+ versionOk: false,
1365
+ detail: "installed but daemon is not running"
1366
+ };
1367
+ }
1368
+ return { name: "Docker", available: false, version: null, versionOk: false, detail: "not found in PATH" };
1369
+ }
1370
+ async function checkInstalled(layout, manifest) {
1371
+ const results = [];
1372
+ const coreCheck = {
1373
+ name: layout.coreDirName,
1374
+ path: join22(layout.coreDir, "node_modules"),
1375
+ exists: await pathExists(join22(layout.coreDir, "node_modules"))
1376
+ };
1377
+ results.push(coreCheck);
1378
+ for (const app of manifest.applications) {
1379
+ const appDir = resolve4(layout.coreDir, app.localPath);
1380
+ const nodeModulesPath = join22(appDir, "node_modules");
1381
+ results.push({
1382
+ name: app.name,
1383
+ path: nodeModulesPath,
1384
+ exists: await pathExists(nodeModulesPath)
1385
+ });
1386
+ }
1387
+ return results;
1388
+ }
1389
+ async function checkBuilt(layout, manifest) {
1390
+ const results = [];
1391
+ const coreTurboPath = join22(layout.coreDir, ".turbo");
1392
+ results.push({
1393
+ name: layout.coreDirName,
1394
+ path: coreTurboPath,
1395
+ exists: await pathExists(coreTurboPath)
1396
+ });
1397
+ for (const app of manifest.applications) {
1398
+ const appDir = resolve4(layout.coreDir, app.localPath);
1399
+ const appTurboPath = join22(appDir, ".turbo");
1400
+ results.push({
1401
+ name: app.name,
1402
+ path: appTurboPath,
1403
+ exists: await pathExists(appTurboPath)
1404
+ });
1405
+ }
1406
+ return results;
1407
+ }
1408
+ async function resolveComposeFiles(layout, manifest) {
1409
+ const { localDir, coreDirName } = layout;
1410
+ const platformName = manifest.product.name;
1411
+ const files = [join22(localDir, "platform-docker-compose.yml")];
1412
+ const prefixedCore = join22(localDir, `${coreDirName}-docker-compose.yml`);
1413
+ const unprefixedCore = join22(localDir, "core-docker-compose.yml");
1414
+ files.push(await pathExists(prefixedCore) ? prefixedCore : unprefixedCore);
1415
+ for (const app of manifest.applications) {
1416
+ const prefixed = join22(localDir, `${platformName}-${app.name}-docker-compose.yml`);
1417
+ const unprefixed = join22(localDir, `${app.name}-docker-compose.yml`);
1418
+ if (await pathExists(prefixed)) files.push(prefixed);
1419
+ else if (await pathExists(unprefixed)) files.push(unprefixed);
1420
+ }
1421
+ return files;
1422
+ }
1423
+ async function checkContainers(layout, manifest) {
1424
+ const platformName = manifest.product.name;
1425
+ const projectName = `${platformName}-platform`;
1426
+ const composeFiles = await resolveComposeFiles(layout, manifest);
1427
+ const fileArgs = composeFiles.flatMap((f) => ["-f", f]);
1428
+ const { code: cfgCode, stdout: cfgOut } = await spawnCapture(
1429
+ "docker",
1430
+ ["compose", "-p", projectName, ...fileArgs, "config", "--services"],
1431
+ layout.rootDir
1432
+ );
1433
+ const expectedServices = cfgCode === 0 ? cfgOut.trim().split("\n").map((s) => s.trim()).filter(Boolean) : [];
1434
+ const { stdout: psOut } = await spawnCapture(
1435
+ "docker",
1436
+ ["compose", "-p", projectName, ...fileArgs, "ps", "--format", "json"],
1437
+ layout.rootDir
1438
+ );
1439
+ const runningByService = /* @__PURE__ */ new Map();
1440
+ for (const line of psOut.trim().split("\n")) {
1441
+ const trimmed = line.trim();
1442
+ if (!trimmed) continue;
1443
+ try {
1444
+ const obj = JSON.parse(trimmed);
1445
+ const service = String(obj["Service"] ?? obj["Name"] ?? "");
1446
+ if (service) {
1447
+ runningByService.set(service, {
1448
+ state: String(obj["State"] ?? "unknown").toLowerCase(),
1449
+ ports: String(obj["Publishers"] ? formatPublishers(obj["Publishers"]) : obj["Ports"] ?? "")
1450
+ });
1451
+ }
1452
+ } catch {
1453
+ }
1454
+ }
1455
+ if (expectedServices.length > 0) {
1456
+ return expectedServices.map((service) => {
1457
+ const actual = runningByService.get(service);
1458
+ return {
1459
+ name: service,
1460
+ state: actual ? actual.state : "not started",
1461
+ ports: actual ? actual.ports : ""
1462
+ };
1463
+ });
1464
+ }
1465
+ return Array.from(runningByService.entries()).map(([name, info]) => ({
1466
+ name,
1467
+ ...info
1468
+ }));
1469
+ }
1470
+ function formatPublishers(publishers) {
1471
+ if (!Array.isArray(publishers)) return "";
1472
+ return publishers.map((p) => {
1473
+ if (typeof p !== "object" || p === null) return "";
1474
+ const pub = p;
1475
+ const host = pub["URL"] ?? "0.0.0.0";
1476
+ const published = pub["PublishedPort"];
1477
+ const target = pub["TargetPort"];
1478
+ const proto = pub["Protocol"] ?? "tcp";
1479
+ if (!published || !target) return "";
1480
+ return `${host}:${published}->${target}/${proto}`;
1481
+ }).filter(Boolean).join(", ");
1482
+ }
1483
+ function computeNextStep(result) {
1484
+ if (!result.lifecycle.initialized) return "init";
1485
+ if (!result.lifecycle.installed) return "install";
1486
+ if (!result.lifecycle.built) return "build";
1487
+ if (!result.lifecycle.running) return "start";
1488
+ return null;
1489
+ }
1490
+ async function gatherStatus() {
1491
+ const layout = await findPlatformLayout();
1492
+ const [nodeCheck, dockerCheck] = await Promise.all([checkNodeVersion(), checkDocker()]);
1493
+ const prerequisites = [nodeCheck, dockerCheck];
1494
+ if (!layout) {
1495
+ return {
1496
+ projectInfo: null,
1497
+ prerequisites,
1498
+ lifecycle: {
1499
+ initialized: false,
1500
+ installed: false,
1501
+ installedDetails: [],
1502
+ built: false,
1503
+ builtDetails: [],
1504
+ running: false
1505
+ },
1506
+ containers: []
1507
+ };
1508
+ }
1509
+ let manifest;
1510
+ try {
1511
+ manifest = await readManifest(layout.rootDir, layout.coreDirName);
1512
+ } catch {
1513
+ return {
1514
+ projectInfo: null,
1515
+ prerequisites,
1516
+ lifecycle: {
1517
+ initialized: true,
1518
+ installed: false,
1519
+ installedDetails: [],
1520
+ built: false,
1521
+ builtDetails: [],
1522
+ running: false
1523
+ },
1524
+ containers: []
1525
+ };
1526
+ }
1527
+ const [installedDetails, builtDetails, containers] = await Promise.all([
1528
+ checkInstalled(layout, manifest),
1529
+ checkBuilt(layout, manifest),
1530
+ checkContainers(layout, manifest)
1531
+ ]);
1532
+ const projectInfo = {
1533
+ productName: manifest.product.name,
1534
+ displayName: manifest.product.displayName,
1535
+ organization: manifest.product.organization,
1536
+ scope: manifest.product.scope,
1537
+ applicationCount: manifest.applications.length,
1538
+ applicationNames: manifest.applications.map((a) => a.name)
1539
+ };
1540
+ return {
1541
+ projectInfo,
1542
+ prerequisites,
1543
+ lifecycle: {
1544
+ initialized: true,
1545
+ installed: installedDetails.every((d) => d.exists),
1546
+ installedDetails,
1547
+ built: builtDetails.every((d) => d.exists),
1548
+ builtDetails,
1549
+ running: containers.length > 0 && containers.every((c) => c.state === "running")
1550
+ },
1551
+ containers
1552
+ };
1553
+ }
1554
+
1555
+ // src/commands/status/status.command.ts
1556
+ var STATUS_COMMAND_NAME = "status";
1557
+ var statusCommand = {
1558
+ name: STATUS_COMMAND_NAME,
1559
+ description: "Show platform status and health checks"
1560
+ };
1561
+
1562
+ // src/commands/local-scripts/docker-compose-orchestrator.ts
1563
+ import { spawn as spawn2 } from "child_process";
1564
+ import { access as access6 } from "fs/promises";
1565
+ import { join as join23 } from "path";
1294
1566
  function runDockerCompose(args2, logger, rootDir, signal) {
1295
1567
  return new Promise((resolvePromise) => {
1296
- const child = spawn("docker", ["compose", ...args2], {
1568
+ const child = spawn2("docker", ["compose", ...args2], {
1297
1569
  shell: false,
1298
1570
  stdio: ["ignore", "pipe", "pipe"],
1299
1571
  cwd: rootDir
@@ -1337,7 +1609,7 @@ function runDockerCompose(args2, logger, rootDir, signal) {
1337
1609
  }
1338
1610
  function captureDockerCompose(args2, rootDir) {
1339
1611
  return new Promise((resolvePromise, reject) => {
1340
- const child = spawn("docker", ["compose", ...args2], {
1612
+ const child = spawn2("docker", ["compose", ...args2], {
1341
1613
  shell: false,
1342
1614
  stdio: ["ignore", "pipe", "pipe"],
1343
1615
  cwd: rootDir
@@ -1356,15 +1628,15 @@ function captureDockerCompose(args2, rootDir) {
1356
1628
  async function getAppComposePaths(localDir, platformName, manifest) {
1357
1629
  const results = [];
1358
1630
  for (const app of manifest.applications) {
1359
- const prefixedPath = join22(localDir, `${platformName}-${app.name}-docker-compose.yml`);
1360
- const unprefixedPath = join22(localDir, `${app.name}-docker-compose.yml`);
1631
+ const prefixedPath = join23(localDir, `${platformName}-${app.name}-docker-compose.yml`);
1632
+ const unprefixedPath = join23(localDir, `${app.name}-docker-compose.yml`);
1361
1633
  let resolved = null;
1362
1634
  try {
1363
- await access5(prefixedPath);
1635
+ await access6(prefixedPath);
1364
1636
  resolved = prefixedPath;
1365
1637
  } catch {
1366
1638
  try {
1367
- await access5(unprefixedPath);
1639
+ await access6(unprefixedPath);
1368
1640
  resolved = unprefixedPath;
1369
1641
  } catch {
1370
1642
  }
@@ -1378,18 +1650,18 @@ async function getAppComposePaths(localDir, platformName, manifest) {
1378
1650
  async function buildFullComposeArgs(layout, manifest, logger) {
1379
1651
  const { coreDirName, localDir } = layout;
1380
1652
  const platformName = manifest.product.name;
1381
- const prefixedCoreCompose = join22(localDir, `${coreDirName}-docker-compose.yml`);
1382
- const unprefixedCoreCompose = join22(localDir, "core-docker-compose.yml");
1653
+ const prefixedCoreCompose = join23(localDir, `${coreDirName}-docker-compose.yml`);
1654
+ const unprefixedCoreCompose = join23(localDir, "core-docker-compose.yml");
1383
1655
  let coreComposePath;
1384
1656
  try {
1385
- await access5(prefixedCoreCompose);
1657
+ await access6(prefixedCoreCompose);
1386
1658
  coreComposePath = prefixedCoreCompose;
1387
1659
  } catch {
1388
1660
  coreComposePath = unprefixedCoreCompose;
1389
1661
  }
1390
1662
  const fileArgs = [
1391
1663
  "-f",
1392
- join22(localDir, "platform-docker-compose.yml"),
1664
+ join23(localDir, "platform-docker-compose.yml"),
1393
1665
  "-f",
1394
1666
  coreComposePath
1395
1667
  ];
@@ -1409,16 +1681,16 @@ async function buildSelectedComposeFiles(layout, selectedManifest, includeCore)
1409
1681
  const platformName = selectedManifest.product.name;
1410
1682
  const files = [];
1411
1683
  if (includeCore) {
1412
- const prefixedCoreCompose = join22(localDir, `${coreDirName}-docker-compose.yml`);
1413
- const unprefixedCoreCompose = join22(localDir, "core-docker-compose.yml");
1684
+ const prefixedCoreCompose = join23(localDir, `${coreDirName}-docker-compose.yml`);
1685
+ const unprefixedCoreCompose = join23(localDir, "core-docker-compose.yml");
1414
1686
  let coreComposePath;
1415
1687
  try {
1416
- await access5(prefixedCoreCompose);
1688
+ await access6(prefixedCoreCompose);
1417
1689
  coreComposePath = prefixedCoreCompose;
1418
1690
  } catch {
1419
1691
  coreComposePath = unprefixedCoreCompose;
1420
1692
  }
1421
- files.push(join22(localDir, "platform-docker-compose.yml"), coreComposePath);
1693
+ files.push(join23(localDir, "platform-docker-compose.yml"), coreComposePath);
1422
1694
  }
1423
1695
  const appEntries = await getAppComposePaths(localDir, platformName, selectedManifest);
1424
1696
  for (const { composePath } of appEntries) {
@@ -1455,7 +1727,7 @@ async function getServicesFromComposeFiles(selectedFiles, allFiles, rootDir) {
1455
1727
  async function startEnvironment(layout, manifest, logger, signal, includeCore = true, fullManifest) {
1456
1728
  const { rootDir, localDir } = layout;
1457
1729
  const platformName = manifest.product.name;
1458
- const envFile = join22(localDir, ".env");
1730
+ const envFile = join23(localDir, ".env");
1459
1731
  const isSelective = fullManifest !== void 0;
1460
1732
  const fileArgs = await buildFullComposeArgs(layout, isSelective ? fullManifest : manifest, logger);
1461
1733
  const projectArgs = ["-p", `${platformName}-platform`, "--project-directory", localDir, "--env-file", envFile];
@@ -1477,7 +1749,7 @@ async function startEnvironment(layout, manifest, logger, signal, includeCore =
1477
1749
  async function stopEnvironment(layout, manifest, logger, signal, includeCore = true, fullManifest) {
1478
1750
  const { rootDir, localDir } = layout;
1479
1751
  const platformName = manifest.product.name;
1480
- const envFile = join22(localDir, ".env");
1752
+ const envFile = join23(localDir, ".env");
1481
1753
  const isSelective = fullManifest !== void 0;
1482
1754
  const fileArgs = await buildFullComposeArgs(layout, isSelective ? fullManifest : manifest, logger);
1483
1755
  const projectArgs = ["-p", `${platformName}-platform`, "--project-directory", localDir, "--env-file", envFile];
@@ -1499,7 +1771,7 @@ async function stopEnvironment(layout, manifest, logger, signal, includeCore = t
1499
1771
  async function destroyEnvironment(layout, manifest, logger, signal, includeCore = true, fullManifest) {
1500
1772
  const { rootDir, localDir } = layout;
1501
1773
  const platformName = manifest.product.name;
1502
- const envFile = join22(localDir, ".env");
1774
+ const envFile = join23(localDir, ".env");
1503
1775
  const isSelective = fullManifest !== void 0;
1504
1776
  const fileArgs = await buildFullComposeArgs(layout, isSelective ? fullManifest : manifest, logger);
1505
1777
  const projectArgs = ["-p", `${platformName}-platform`, "--project-directory", localDir, "--env-file", envFile];
@@ -1523,12 +1795,12 @@ async function destroyEnvironment(layout, manifest, logger, signal, includeCore
1523
1795
  }
1524
1796
 
1525
1797
  // src/commands/local-scripts/npm-orchestrator.ts
1526
- import { spawn as spawn2 } from "child_process";
1527
- import { access as access6 } from "fs/promises";
1528
- import { resolve as resolve4, join as join23 } from "path";
1798
+ import { spawn as spawn3 } from "child_process";
1799
+ import { access as access7 } from "fs/promises";
1800
+ import { resolve as resolve5, join as join24 } from "path";
1529
1801
  function runCommand(command, args2, workDir, logger, signal) {
1530
1802
  return new Promise((resolvePromise) => {
1531
- const child = spawn2(command, args2, {
1803
+ const child = spawn3(command, args2, {
1532
1804
  cwd: workDir,
1533
1805
  shell: false,
1534
1806
  stdio: ["ignore", "pipe", "pipe"]
@@ -1572,7 +1844,7 @@ function runCommand(command, args2, workDir, logger, signal) {
1572
1844
  }
1573
1845
  async function dirExists(dirPath) {
1574
1846
  try {
1575
- await access6(dirPath);
1847
+ await access7(dirPath);
1576
1848
  return true;
1577
1849
  } catch {
1578
1850
  return false;
@@ -1582,7 +1854,7 @@ async function installDependencies(layout, manifest, logger, signal, includeCore
1582
1854
  const { coreDir, coreDirName } = layout;
1583
1855
  const appDirs = [];
1584
1856
  for (const app of manifest.applications) {
1585
- const appDir = resolve4(join23(coreDir), app.localPath);
1857
+ const appDir = resolve5(join24(coreDir), app.localPath);
1586
1858
  if (!await dirExists(appDir)) {
1587
1859
  logger.log(`Warning: Application directory "${app.name}" not found at ${appDir} \u2014 skipping install.`);
1588
1860
  continue;
@@ -1608,7 +1880,7 @@ async function buildAll(layout, manifest, logger, signal, includeCore = true) {
1608
1880
  }
1609
1881
  const appDirs = [];
1610
1882
  for (const app of manifest.applications) {
1611
- const appDir = resolve4(join23(coreDir), app.localPath);
1883
+ const appDir = resolve5(join24(coreDir), app.localPath);
1612
1884
  if (!await dirExists(appDir)) {
1613
1885
  logger.log(`Warning: Application directory "${app.name}" not found at ${appDir} \u2014 skipping build.`);
1614
1886
  continue;
@@ -1635,23 +1907,28 @@ var DESTROY_COMMAND_NAME = "destroy";
1635
1907
  var CORE_APP_NAME = "core";
1636
1908
  var installCommand = {
1637
1909
  name: INSTALL_COMMAND_NAME,
1638
- description: "Install dependencies in the local dev environment"
1910
+ description: "Install dependencies in the local dev environment",
1911
+ hidden: (ctx) => !ctx.platformInitialized
1639
1912
  };
1640
1913
  var buildCommand = {
1641
1914
  name: BUILD_COMMAND_NAME,
1642
- description: "Build the local dev environment"
1915
+ description: "Build the local dev environment",
1916
+ hidden: (ctx) => !ctx.platformInitialized
1643
1917
  };
1644
1918
  var startCommand = {
1645
1919
  name: START_COMMAND_NAME,
1646
- description: "Start the local dev environment"
1920
+ description: "Start the local dev environment",
1921
+ hidden: (ctx) => !ctx.platformInitialized
1647
1922
  };
1648
1923
  var stopCommand = {
1649
1924
  name: STOP_COMMAND_NAME,
1650
- description: "Stop the local dev environment"
1925
+ description: "Stop the local dev environment",
1926
+ hidden: (ctx) => !ctx.platformInitialized
1651
1927
  };
1652
1928
  var destroyCommand = {
1653
1929
  name: DESTROY_COMMAND_NAME,
1654
- description: "Destroy the local dev environment"
1930
+ description: "Destroy the local dev environment",
1931
+ hidden: (ctx) => !ctx.platformInitialized
1655
1932
  };
1656
1933
  var localScriptCommands = [
1657
1934
  installCommand,
@@ -1744,14 +2021,15 @@ var CommandRegistry = class {
1744
2021
  }
1745
2022
  };
1746
2023
  var registry = new CommandRegistry();
1747
- registry.register({ ...createApplicationCommand, hidden: (ctx) => !ctx.platformInitialized });
1748
2024
  registry.register(initCommand);
1749
- registry.register({ ...configureIdpCommand, hidden: (ctx) => !ctx.platformInitialized });
1750
- registry.register({ ...createServiceModuleCommand, hidden: (ctx) => !ctx.platformInitialized });
1751
- registry.register({ ...createUiModuleCommand, hidden: (ctx) => !ctx.platformInitialized });
2025
+ registry.register(configureIdpCommand);
2026
+ registry.register(createApplicationCommand);
2027
+ registry.register(createServiceModuleCommand);
2028
+ registry.register(createUiModuleCommand);
1752
2029
  for (const cmd of localScriptCommands) {
1753
- registry.register({ ...cmd, hidden: (ctx) => !ctx.platformInitialized });
2030
+ registry.register(cmd);
1754
2031
  }
2032
+ registry.register(statusCommand);
1755
2033
 
1756
2034
  // src/app-state.ts
1757
2035
  var APP_STATE = {
@@ -1958,11 +2236,121 @@ async function createUiModuleUiController(ctx) {
1958
2236
  );
1959
2237
  }
1960
2238
 
2239
+ // src/services/status.service.ts
2240
+ async function statusService() {
2241
+ return gatherStatus();
2242
+ }
2243
+
2244
+ // src/utils/theme.ts
2245
+ import chalk from "chalk";
2246
+ var theme = {
2247
+ prompt: chalk.green,
2248
+ commandName: chalk.cyan,
2249
+ commandDescription: chalk.gray,
2250
+ selected: chalk.bgBlue.white,
2251
+ output: chalk.white,
2252
+ muted: chalk.dim,
2253
+ error: chalk.red,
2254
+ success: chalk.green,
2255
+ warning: chalk.yellow,
2256
+ info: chalk.cyan,
2257
+ section: chalk.bold.white,
2258
+ label: chalk.dim
2259
+ };
2260
+
2261
+ // src/commands/status/status-formatter.ts
2262
+ var CHECK = theme.success("\u2713");
2263
+ var CROSS = theme.error("\u2717");
2264
+ function tick(ok) {
2265
+ return ok ? CHECK : CROSS;
2266
+ }
2267
+ function formatStatusLines(result) {
2268
+ const lines = [];
2269
+ if (result.projectInfo) {
2270
+ const p = result.projectInfo;
2271
+ lines.push(theme.info("\u25B8 ") + theme.section(p.displayName) + theme.label(` (${p.productName})`));
2272
+ lines.push(theme.label(" Organization: ") + p.organization + theme.label(` (${p.scope})`));
2273
+ const appList = p.applicationNames.length > 0 ? p.applicationNames.join(", ") : "(none)";
2274
+ lines.push(theme.label(" Applications: ") + `${p.applicationCount} \u2014 ` + appList);
2275
+ lines.push("");
2276
+ }
2277
+ lines.push(theme.section("Prerequisites"));
2278
+ for (const pre of result.prerequisites) {
2279
+ const ok = pre.available && pre.versionOk;
2280
+ const versionStr = pre.version ? theme.label(` ${pre.version}`) : "";
2281
+ const detailStr = pre.detail ? theme.warning(` \u2014 ${pre.detail}`) : "";
2282
+ lines.push(` ${tick(ok)} ${pre.name}${versionStr}${detailStr}`);
2283
+ }
2284
+ lines.push("");
2285
+ lines.push(theme.section("Lifecycle"));
2286
+ lines.push(` ${tick(result.lifecycle.initialized)} Platform initialized`);
2287
+ const installed = result.lifecycle.installed;
2288
+ lines.push(` ${tick(installed)} Dependencies installed`);
2289
+ if (!installed && result.lifecycle.installedDetails.length > 0) {
2290
+ for (const d of result.lifecycle.installedDetails) {
2291
+ if (!d.exists) {
2292
+ lines.push(` ${CROSS} ${theme.label(d.name)} ${theme.warning("(missing node_modules/)")}`);
2293
+ }
2294
+ }
2295
+ }
2296
+ const built = result.lifecycle.built;
2297
+ lines.push(` ${tick(built)} Build completed`);
2298
+ if (!built && result.lifecycle.builtDetails.length > 0) {
2299
+ for (const d of result.lifecycle.builtDetails) {
2300
+ if (!d.exists) {
2301
+ lines.push(` ${CROSS} ${theme.label(d.name)} ${theme.warning("(missing .turbo/)")}`);
2302
+ }
2303
+ }
2304
+ }
2305
+ lines.push(` ${tick(result.lifecycle.running)} Environment running`);
2306
+ if (result.containers.length > 0) {
2307
+ lines.push("");
2308
+ lines.push(theme.section("Containers"));
2309
+ for (const c of result.containers) {
2310
+ const ok = c.state === "running";
2311
+ const stateStr = ok ? theme.success(c.state) : c.state === "not started" ? theme.label(c.state) : theme.error(c.state);
2312
+ const ports = c.ports ? theme.label(` ${c.ports}`) : "";
2313
+ lines.push(` ${tick(ok)} ${c.name.padEnd(35)} ${stateStr}${ports}`);
2314
+ }
2315
+ }
2316
+ return lines;
2317
+ }
2318
+
1961
2319
  // src/services/local-script.service.ts
1962
2320
  async function localScriptService(scriptName, logger, signal, appNames) {
1963
2321
  await runLocalScript(scriptName, logger, signal, appNames);
1964
2322
  }
1965
2323
 
2324
+ // src/controllers/ui/status.ui-controller.ts
2325
+ async function statusUiController(ctx) {
2326
+ while (true) {
2327
+ const result = await statusService();
2328
+ for (const line of formatStatusLines(result)) {
2329
+ ctx.log(line);
2330
+ }
2331
+ const next = computeNextStep(result);
2332
+ if (next === null) {
2333
+ ctx.log("");
2334
+ ctx.log("All checks passed!");
2335
+ return;
2336
+ }
2337
+ const shouldRun = await ctx.confirm(`Next step: "${next}". Run it now?`, true);
2338
+ if (!shouldRun) return;
2339
+ if (next === "init") {
2340
+ await initUiController(ctx);
2341
+ } else {
2342
+ await localScriptService(next, ctx, ctx.signal);
2343
+ }
2344
+ const resultAfter = await statusService();
2345
+ const nextAfter = computeNextStep(resultAfter);
2346
+ if (nextAfter === next) {
2347
+ ctx.log("");
2348
+ ctx.log(`"${next}" did not complete successfully. Check the output above for errors.`);
2349
+ return;
2350
+ }
2351
+ }
2352
+ }
2353
+
1966
2354
  // src/controllers/ui/local-script.ui-controller.ts
1967
2355
  function createLocalScriptUiController(scriptName) {
1968
2356
  return async (ctx) => {
@@ -2008,6 +2396,7 @@ var uiControllers = /* @__PURE__ */ new Map([
2008
2396
  [CONFIGURE_IDP_COMMAND_NAME, configureIdpUiController],
2009
2397
  [CREATE_SERVICE_MODULE_COMMAND_NAME, createServiceModuleUiController],
2010
2398
  [CREATE_UI_MODULE_COMMAND_NAME, createUiModuleUiController],
2399
+ [STATUS_COMMAND_NAME, statusUiController],
2011
2400
  [INSTALL_COMMAND_NAME, createLocalScriptUiController(INSTALL_COMMAND_NAME)],
2012
2401
  [BUILD_COMMAND_NAME, createLocalScriptUiController(BUILD_COMMAND_NAME)],
2013
2402
  [START_COMMAND_NAME, createLocalScriptUiController(START_COMMAND_NAME)],
@@ -2046,7 +2435,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2046
2435
  }
2047
2436
  },
2048
2437
  prompt(message, defaultValue) {
2049
- return new Promise((resolve5, reject) => {
2438
+ return new Promise((resolve6, reject) => {
2050
2439
  if (controller.signal.aborted) {
2051
2440
  reject(new DOMException("Aborted", "AbortError"));
2052
2441
  return;
@@ -2054,7 +2443,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2054
2443
  setPromptMessage(message);
2055
2444
  setPromptValue(defaultValue ?? "");
2056
2445
  setPromptMode({ kind: "text" });
2057
- promptResolveRef.current = resolve5;
2446
+ promptResolveRef.current = resolve6;
2058
2447
  setState(APP_STATE.PROMPTING);
2059
2448
  controller.signal.addEventListener(
2060
2449
  "abort",
@@ -2064,7 +2453,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2064
2453
  });
2065
2454
  },
2066
2455
  select(message, options) {
2067
- return new Promise((resolve5, reject) => {
2456
+ return new Promise((resolve6, reject) => {
2068
2457
  if (controller.signal.aborted) {
2069
2458
  reject(new DOMException("Aborted", "AbortError"));
2070
2459
  return;
@@ -2072,7 +2461,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2072
2461
  setPromptMessage(message);
2073
2462
  setPromptMode({ kind: "select", options });
2074
2463
  setSelectIndex(0);
2075
- promptResolveRef.current = resolve5;
2464
+ promptResolveRef.current = resolve6;
2076
2465
  setState(APP_STATE.PROMPTING);
2077
2466
  controller.signal.addEventListener(
2078
2467
  "abort",
@@ -2082,7 +2471,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2082
2471
  });
2083
2472
  },
2084
2473
  multiselect(message, options) {
2085
- return new Promise((resolve5, reject) => {
2474
+ return new Promise((resolve6, reject) => {
2086
2475
  if (controller.signal.aborted) {
2087
2476
  reject(new DOMException("Aborted", "AbortError"));
2088
2477
  return;
@@ -2092,7 +2481,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2092
2481
  setSelectIndex(0);
2093
2482
  setMultiselectChecked(new Set(options.map((_, i) => i)));
2094
2483
  promptResolveRef.current = (value) => {
2095
- resolve5(value ? value.split(",") : []);
2484
+ resolve6(value ? value.split(",") : []);
2096
2485
  };
2097
2486
  setState(APP_STATE.PROMPTING);
2098
2487
  controller.signal.addEventListener(
@@ -2103,7 +2492,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2103
2492
  });
2104
2493
  },
2105
2494
  confirm(message, defaultValue) {
2106
- return new Promise((resolve5, reject) => {
2495
+ return new Promise((resolve6, reject) => {
2107
2496
  if (controller.signal.aborted) {
2108
2497
  reject(new DOMException("Aborted", "AbortError"));
2109
2498
  return;
@@ -2111,7 +2500,7 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2111
2500
  setPromptMessage(message);
2112
2501
  setPromptMode({ kind: "confirm" });
2113
2502
  setConfirmValue(defaultValue ?? true);
2114
- promptResolveRef.current = (value) => resolve5(value === "true");
2503
+ promptResolveRef.current = (value) => resolve6(value === "true");
2115
2504
  setState(APP_STATE.PROMPTING);
2116
2505
  controller.signal.addEventListener(
2117
2506
  "abort",
@@ -2145,11 +2534,11 @@ function useCommandRunner({ appendStaticItem, setState, onCommandComplete }) {
2145
2534
  );
2146
2535
  const handlePromptSubmit = useCallback(
2147
2536
  (value) => {
2148
- const resolve5 = promptResolveRef.current;
2537
+ const resolve6 = promptResolveRef.current;
2149
2538
  promptResolveRef.current = null;
2150
2539
  setPromptMode({ kind: "text" });
2151
2540
  setState(APP_STATE.EXECUTING);
2152
- resolve5?.(value);
2541
+ resolve6?.(value);
2153
2542
  },
2154
2543
  [setState]
2155
2544
  );
@@ -2557,6 +2946,21 @@ async function createUiModuleCliController(args2) {
2557
2946
  );
2558
2947
  }
2559
2948
 
2949
+ // src/controllers/cli/status.cli-controller.ts
2950
+ var statusCliController = async (_args) => {
2951
+ const result = await statusService();
2952
+ const lines = formatStatusLines(result);
2953
+ for (const line of lines) {
2954
+ console.log(line);
2955
+ }
2956
+ const next = computeNextStep(result);
2957
+ if (next !== null) {
2958
+ console.log("");
2959
+ console.log(`Hint: Run "platform ${next}" to continue.`);
2960
+ process.exit(1);
2961
+ }
2962
+ };
2963
+
2560
2964
  // src/controllers/cli/registry.ts
2561
2965
  var cliControllers = /* @__PURE__ */ new Map([
2562
2966
  [CREATE_APPLICATION_COMMAND_NAME, createApplicationCliController],
@@ -2564,6 +2968,7 @@ var cliControllers = /* @__PURE__ */ new Map([
2564
2968
  [CONFIGURE_IDP_COMMAND_NAME, configureIdpCliController],
2565
2969
  [CREATE_SERVICE_MODULE_COMMAND_NAME, createServiceModuleCliController],
2566
2970
  [CREATE_UI_MODULE_COMMAND_NAME, createUiModuleCliController],
2971
+ [STATUS_COMMAND_NAME, statusCliController],
2567
2972
  [INSTALL_COMMAND_NAME, createLocalScriptCliController(INSTALL_COMMAND_NAME)],
2568
2973
  [BUILD_COMMAND_NAME, createLocalScriptCliController(BUILD_COMMAND_NAME)],
2569
2974
  [START_COMMAND_NAME, createLocalScriptCliController(START_COMMAND_NAME)],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluealba/platform-cli",
3
- "version": "0.3.1-feature-add-new-commands-226",
3
+ "version": "0.3.1-feature-platform-cli-228",
4
4
  "description": "Blue Alba Platform CLI",
5
5
  "license": "PolyForm-Noncommercial-1.0.0",
6
6
  "type": "module",
@@ -5,7 +5,7 @@ ENV PORT=3000
5
5
 
6
6
  RUN apk -U upgrade --no-cache
7
7
 
8
- WORKDIR /app/out/{{bootstrapName}}-bootstrap-service
8
+ WORKDIR /app/out/{{bootstrapServiceName}}
9
9
 
10
10
  COPY ./out/ /app/out
11
11
 
@@ -3,7 +3,7 @@ FROM node:20.11-alpine as development
3
3
  ENV NODE_ENV=development
4
4
  ENV PORT=80
5
5
 
6
- WORKDIR /app/out/{{bootstrapServiceDir}}/{{bootstrapName}}-bootstrap-service
6
+ WORKDIR /app/out/{{bootstrapServiceDir}}/{{bootstrapServiceName}}
7
7
 
8
8
  EXPOSE 80
9
9
 
@@ -1,4 +1,4 @@
1
- # {{bootstrapName}}-bootstrap-service
1
+ # {{bootstrapServiceName}}
2
2
 
3
3
  A service that defines the {{platformTitle}} elements such as modules, operations, roles, etc.
4
4
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@{{organizationName}}/{{bootstrapName}}-bootstrap-service",
2
+ "name": "@{{organizationName}}/{{bootstrapServiceName}}",
3
3
  "displayName": "{{platformTitle}} Bootstrap Service",
4
4
  "version": "0.1.0",
5
5
  "private": true,
@@ -1,12 +1,12 @@
1
1
  # Core Services
2
2
  services:
3
- {{platformName}}-bootstrap-service:
3
+ {{bootstrapServiceName}}:
4
4
  build:
5
- context: ../services/{{platformName}}-bootstrap-service
5
+ context: ../services/{{bootstrapServiceName}}
6
6
  dockerfile: Dockerfile.development
7
7
  environment:
8
8
  - NODE_TLS_REJECT_UNAUTHORIZED=0
9
- - SERVICE_ACCESS_NAME={{platformName}}-bootstrap-service
9
+ - SERVICE_ACCESS_NAME={{bootstrapServiceName}}
10
10
  - WAIT_TIME=5000
11
11
  - SYNC_STRATEGY=${PAE_BOOTSTRAP_SYNC_STRATEGY}
12
12
  - GATEWAY_SERVICE_URL=${PAE_GATEWAY_URL}
@@ -17,9 +17,9 @@ services:
17
17
  pae-nestjs-gateway-service:
18
18
  condition: service_healthy
19
19
 
20
- {{platformName}}-customization-ui:
20
+ {{customizationUiName}}:
21
21
  build:
22
- context: ../ui/{{platformName}}-customization-ui
22
+ context: ../ui/{{customizationUiName}}
23
23
  dockerfile: Dockerfile.development
24
24
  ports:
25
25
  - 9446:80