@bluealba/platform-cli 0.3.0 → 0.3.1

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.
Files changed (32) hide show
  1. package/dist/index.js +220 -208
  2. package/package.json +1 -1
  3. package/templates/customization-ui-module-template/Dockerfile +4 -4
  4. package/templates/customization-ui-module-template/Dockerfile.development +1 -1
  5. package/templates/customization-ui-module-template/package.json +3 -3
  6. package/templates/customization-ui-module-template/tsconfig.json +1 -1
  7. package/templates/customization-ui-module-template/webpack.config.js +2 -2
  8. package/templates/platform-init-template/{local → {{platformName}}-local}/.env.example +1 -1
  9. package/templates/platform-init-template/{{platformName}}-local/docker-compose.yml +3 -0
  10. package/templates/platform-init-template/{local → {{platformName}}-local}/package.json +3 -3
  11. package/templates/platform-init-template/{local → {{platformName}}-local}/scripts/build.sh +1 -1
  12. package/templates/platform-init-template/{local → {{platformName}}-local}/scripts/install.sh +1 -1
  13. package/templates/platform-init-template/{local/core-docker-compose.yml → {{platformName}}-local/{{platformName}}-core-docker-compose.yml} +5 -5
  14. package/templates/react-ui-module-template/Dockerfile +3 -3
  15. package/templates/react-ui-module-template/Dockerfile.development +1 -1
  16. package/templates/react-ui-module-template/package.json +1 -1
  17. package/templates/platform-init-template/local/docker-compose.yml +0 -3
  18. /package/templates/customization-ui-module-template/src/{platform-customization-ui.tsx → {{platformName}}-customization-ui.tsx} +0 -0
  19. /package/templates/platform-init-template/{core → {{platformName}}-core}/.changeset/config.json +0 -0
  20. /package/templates/platform-init-template/{core → {{platformName}}-core}/.nvmrc +0 -0
  21. /package/templates/platform-init-template/{core → {{platformName}}-core}/.syncpackrc +0 -0
  22. /package/templates/platform-init-template/{core → {{platformName}}-core}/package.json +0 -0
  23. /package/templates/platform-init-template/{core → {{platformName}}-core}/packages-versions.json +0 -0
  24. /package/templates/platform-init-template/{core → {{platformName}}-core}/scripts/preinstall.mjs +0 -0
  25. /package/templates/platform-init-template/{core → {{platformName}}-core}/services/.gitkeep +0 -0
  26. /package/templates/platform-init-template/{core → {{platformName}}-core}/turbo.json +0 -0
  27. /package/templates/platform-init-template/{core → {{platformName}}-core}/ui/.gitkeep +0 -0
  28. /package/templates/platform-init-template/{local → {{platformName}}-local}/environment/pae-nestjs-gateway-service.env +0 -0
  29. /package/templates/platform-init-template/{local → {{platformName}}-local}/nginx.conf +0 -0
  30. /package/templates/platform-init-template/{local → {{platformName}}-local}/platform-docker-compose.yml +0 -0
  31. /package/templates/platform-init-template/{local → {{platformName}}-local}/ssl/cert.pem +0 -0
  32. /package/templates/platform-init-template/{local → {{platformName}}-local}/ssl/key.pem +0 -0
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { render } from "ink";
6
6
  // src/app.tsx
7
7
  import { createRequire } from "module";
8
8
  import { useState as useState3, useCallback as useCallback2 } from "react";
9
- import { Box as Box4, Text as Text6, useApp, useInput } from "ink";
9
+ import { Box as Box5, Text as Text7, useApp, useInput } from "ink";
10
10
 
11
11
  // src/components/prompt.tsx
12
12
  import { Box, Text } from "ink";
@@ -54,53 +54,71 @@ var CommandPalette = React.memo(function CommandPalette2({ commands, selectedInd
54
54
  });
55
55
 
56
56
  // src/components/scrollback-history.tsx
57
- import { Static, Text as Text4 } from "ink";
57
+ import { Static, Text as Text5 } from "ink";
58
58
 
59
59
  // src/components/welcome-banner.tsx
60
+ import React3 from "react";
61
+ import { Box as Box4, Text as Text4 } from "ink";
62
+
63
+ // src/components/working-directory.tsx
60
64
  import React2 from "react";
65
+ import os from "os";
61
66
  import { Box as Box3, Text as Text3 } from "ink";
62
67
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
68
+ var WorkingDirectory = React2.memo(function WorkingDirectory2() {
69
+ const cwd7 = process.cwd();
70
+ const home = os.homedir();
71
+ const displayPath = cwd7.startsWith(home) ? "~" + cwd7.slice(home.length) : cwd7;
72
+ return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
73
+ /* @__PURE__ */ jsx3(Text3, { bold: true, dimColor: true, children: "Working Dir: " }),
74
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: displayPath })
75
+ ] });
76
+ });
77
+
78
+ // src/components/welcome-banner.tsx
79
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
63
80
  var ASCII_ART = [
64
81
  "|---. .---|",
65
82
  "| \\/ |",
66
83
  "| /\\ |",
67
84
  "|---' '---|"
68
85
  ];
69
- var WelcomeBanner = React2.memo(function WelcomeBanner2({ version: version2 }) {
70
- return /* @__PURE__ */ jsxs3(Box3, { borderStyle: "round", flexDirection: "column", paddingX: 1, paddingY: 1, children: [
71
- /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "cyan", children: [
86
+ var WelcomeBanner = React3.memo(function WelcomeBanner2({ version: version2 }) {
87
+ return /* @__PURE__ */ jsxs4(Box4, { borderStyle: "round", flexDirection: "column", paddingX: 1, paddingY: 1, children: [
88
+ /* @__PURE__ */ jsxs4(Text4, { bold: true, color: "cyan", children: [
72
89
  "Blue Alba Platform CLI v",
73
90
  version2
74
91
  ] }),
75
- /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
76
- /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginRight: 2, children: ASCII_ART.map((line, i) => /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: line }, i)) }),
77
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", justifyContent: "center", marginRight: 2, children: [
78
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Welcome to the" }),
79
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Blue Alba Platform!" })
92
+ /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
93
+ /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginRight: 2, children: ASCII_ART.map((line, i) => /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: line }, i)) }),
94
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", justifyContent: "center", marginRight: 2, children: [
95
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Welcome to the" }),
96
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Blue Alba Platform!" })
80
97
  ] }),
81
- /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: ASCII_ART.map((_, i) => /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2502" }, i)) }),
82
- /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 2, children: [
83
- /* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Tips for getting started" }),
84
- /* @__PURE__ */ jsxs3(Text3, { children: [
98
+ /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: ASCII_ART.map((_, i) => /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "\u2502" }, i)) }),
99
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginLeft: 2, children: [
100
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "Tips for getting started" }),
101
+ /* @__PURE__ */ jsxs4(Text4, { children: [
85
102
  "Run ",
86
- /* @__PURE__ */ jsx3(Text3, { color: "green", children: "/init" }),
103
+ /* @__PURE__ */ jsx4(Text4, { color: "green", children: "/init" }),
87
104
  " to start building a platform"
88
105
  ] })
89
106
  ] })
90
- ] })
107
+ ] }),
108
+ /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(WorkingDirectory, {}) })
91
109
  ] });
92
110
  });
93
111
 
94
112
  // src/components/scrollback-history.tsx
95
- import { jsx as jsx4 } from "react/jsx-runtime";
113
+ import { jsx as jsx5 } from "react/jsx-runtime";
96
114
  function ScrollbackHistory({ items, version: version2 }) {
97
- return /* @__PURE__ */ jsx4(Static, { items, children: (item) => item.kind === "banner" ? /* @__PURE__ */ jsx4(WelcomeBanner, { version: version2 }, item.id) : /* @__PURE__ */ jsx4(Text4, { children: item.line }, item.id) });
115
+ return /* @__PURE__ */ jsx5(Static, { items, children: (item) => item.kind === "banner" ? /* @__PURE__ */ jsx5(WelcomeBanner, { version: version2 }, item.id) : /* @__PURE__ */ jsx5(Text5, { children: item.line }, item.id) });
98
116
  }
99
117
 
100
118
  // src/components/spinner.tsx
101
119
  import { useState, useEffect } from "react";
102
- import { Text as Text5 } from "ink";
103
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
120
+ import { Text as Text6 } from "ink";
121
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
104
122
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
105
123
  var INTERVAL_MS = 80;
106
124
  function Spinner({ label }) {
@@ -111,12 +129,12 @@ function Spinner({ label }) {
111
129
  }, INTERVAL_MS);
112
130
  return () => clearInterval(id);
113
131
  }, []);
114
- return /* @__PURE__ */ jsxs4(Text5, { children: [
115
- /* @__PURE__ */ jsxs4(Text5, { color: "cyan", children: [
132
+ return /* @__PURE__ */ jsxs5(Text6, { children: [
133
+ /* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
116
134
  FRAMES[frame],
117
135
  " "
118
136
  ] }),
119
- label && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: label })
137
+ label && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: label })
120
138
  ] });
121
139
  }
122
140
 
@@ -269,7 +287,7 @@ var reactUiModuleTemplateDir = join5(
269
287
  "react-ui-module-template"
270
288
  );
271
289
  async function scaffoldUiModule(uiDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger) {
272
- logger.log(`Creating UI module "${applicationName}-ui"...`);
290
+ logger.log(`Creating UI module "${platformName}-${applicationName}-ui"...`);
273
291
  await applyTemplate(
274
292
  {
275
293
  templateDir: reactUiModuleTemplateDir,
@@ -290,8 +308,8 @@ var nestjsServiceModuleTemplateDir = join6(
290
308
  "templates",
291
309
  "nestjs-service-module-template"
292
310
  );
293
- async function scaffoldNestjsService(serviceDir, organizationName, applicationName, applicationDisplayName, serviceBaseDir, logger) {
294
- const serviceName = `${applicationName}-service`;
311
+ async function scaffoldNestjsService(serviceDir, organizationName, platformName, applicationName, applicationDisplayName, serviceBaseDir, logger) {
312
+ const serviceName = `${platformName}-${applicationName}-service`;
295
313
  const serviceDisplayName = `${applicationDisplayName} Service`;
296
314
  logger.log(`Creating NestJS service "${serviceName}"...`);
297
315
  await applyTemplate(
@@ -322,33 +340,33 @@ async function addModuleEntry(bootstrapServiceDir, applicationName, entry, logge
322
340
  }
323
341
 
324
342
  // src/commands/create-application/module-entry-builders.ts
325
- function buildServiceModuleEntry(organizationName, applicationName, applicationDisplayName) {
343
+ function buildServiceModuleEntry(organizationName, platformName, applicationName, applicationDisplayName) {
326
344
  return {
327
- name: `@${organizationName}/${applicationName}-service`,
345
+ name: `@${organizationName}/${platformName}-${applicationName}-service`,
328
346
  displayName: `${applicationDisplayName} Service`,
329
347
  type: "service",
330
- baseUrl: `/${applicationName}-service`,
348
+ baseUrl: `/${platformName}-${applicationName}-service`,
331
349
  service: {
332
- host: `${applicationName}-service`,
350
+ host: `${platformName}-${applicationName}-service`,
333
351
  port: 80
334
352
  },
335
353
  dependsOn: []
336
354
  };
337
355
  }
338
- function buildUiModuleEntry(organizationName, applicationName, applicationDisplayName) {
356
+ function buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName) {
339
357
  return {
340
- name: `@${organizationName}/${applicationName}-ui`,
358
+ name: `@${organizationName}/${platformName}-${applicationName}-ui`,
341
359
  displayName: applicationDisplayName,
342
360
  type: "app",
343
- baseUrl: `/${applicationName}-ui`,
361
+ baseUrl: `/${platformName}-${applicationName}-ui`,
344
362
  service: {
345
- host: `${applicationName}-ui`,
363
+ host: `${platformName}-${applicationName}-ui`,
346
364
  port: 80
347
365
  },
348
366
  ui: {
349
367
  route: `/${applicationName}`,
350
368
  mountAtSelector: "#pae-shell-ui-content",
351
- bundleFile: `${organizationName}-${applicationName}-ui.js`,
369
+ bundleFile: `${organizationName}-${platformName}-${applicationName}-ui.js`,
352
370
  customProps: {}
353
371
  },
354
372
  dependsOn: [`@bluealba/pae-shell-ui`]
@@ -357,14 +375,14 @@ function buildUiModuleEntry(organizationName, applicationName, applicationDispla
357
375
 
358
376
  // src/commands/create-application/create-docker-compose.ts
359
377
  import { writeFile as writeFile3 } from "fs/promises";
360
- function buildBootstrapBlock(applicationName) {
361
- return ` ${applicationName}-bootstrap-service:
378
+ function buildBootstrapBlock(platformName, applicationName) {
379
+ return ` ${platformName}-${applicationName}-bootstrap-service:
362
380
  build:
363
- context: ../${applicationName}/services/${applicationName}-bootstrap-service
381
+ context: ../${platformName}-${applicationName}/services/${platformName}-${applicationName}-bootstrap-service
364
382
  dockerfile: Dockerfile.development
365
383
  environment:
366
384
  - NODE_TLS_REJECT_UNAUTHORIZED=0
367
- - SERVICE_ACCESS_NAME=${applicationName}-bootstrap
385
+ - SERVICE_ACCESS_NAME=${platformName}-${applicationName}-bootstrap
368
386
  - WAIT_TIME=5000
369
387
  - SYNC_STRATEGY=\${PAE_BOOTSTRAP_SYNC_STRATEGY}
370
388
  - GATEWAY_SERVICE_URL=\${PAE_GATEWAY_URL}
@@ -376,10 +394,10 @@ function buildBootstrapBlock(applicationName) {
376
394
  condition: service_healthy
377
395
  `;
378
396
  }
379
- function buildUiBlock(applicationName, uiPort) {
380
- return ` ${applicationName}-ui:
397
+ function buildUiBlock(platformName, applicationName, uiPort) {
398
+ return ` ${platformName}-${applicationName}-ui:
381
399
  build:
382
- context: ../${applicationName}/ui/${applicationName}-ui
400
+ context: ../${platformName}-${applicationName}/ui/${platformName}-${applicationName}-ui
383
401
  dockerfile: Dockerfile.development
384
402
  ports:
385
403
  - ${uiPort}:80
@@ -387,10 +405,10 @@ function buildUiBlock(applicationName, uiPort) {
387
405
  - \${PWD}/../:/app/out
388
406
  `;
389
407
  }
390
- function buildBackendBlock(applicationName, servicePort) {
391
- return ` ${applicationName}-service:
408
+ function buildBackendBlock(platformName, applicationName, servicePort) {
409
+ return ` ${platformName}-${applicationName}-service:
392
410
  build:
393
- context: ../${applicationName}/services/${applicationName}-service
411
+ context: ../${platformName}-${applicationName}/services/${platformName}-${applicationName}-service
394
412
  dockerfile: Dockerfile.development
395
413
  args:
396
414
  - BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
@@ -402,13 +420,13 @@ function buildBackendBlock(applicationName, servicePort) {
402
420
  - \${PWD}/../:/app/out
403
421
  `;
404
422
  }
405
- async function createDockerCompose(dockerComposePath, applicationName, hasUserInterface, hasBackendService, uiPort, servicePort, logger) {
406
- const blocks = ["services:\n", buildBootstrapBlock(applicationName)];
423
+ async function createDockerCompose(dockerComposePath, platformName, applicationName, hasUserInterface, hasBackendService, uiPort, servicePort, logger) {
424
+ const blocks = ["services:\n", buildBootstrapBlock(platformName, applicationName)];
407
425
  if (hasUserInterface) {
408
- blocks.push(buildUiBlock(applicationName, uiPort));
426
+ blocks.push(buildUiBlock(platformName, applicationName, uiPort));
409
427
  }
410
428
  if (hasBackendService) {
411
- blocks.push(buildBackendBlock(applicationName, servicePort));
429
+ blocks.push(buildBackendBlock(platformName, applicationName, servicePort));
412
430
  }
413
431
  const content = blocks.join("\n");
414
432
  try {
@@ -422,10 +440,10 @@ async function createDockerCompose(dockerComposePath, applicationName, hasUserIn
422
440
 
423
441
  // src/commands/create-application/update-root-docker-compose.ts
424
442
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
425
- async function updateRootDockerCompose(rootDockerComposePath, applicationName, logger) {
443
+ async function updateRootDockerCompose(rootDockerComposePath, platformName, applicationName, logger) {
426
444
  try {
427
445
  const existing = await readFile3(rootDockerComposePath, "utf-8");
428
- const includeLine = ` - path: ./${applicationName}-docker-compose.yml
446
+ const includeLine = ` - path: ./${platformName}-${applicationName}-docker-compose.yml
429
447
  `;
430
448
  await writeFile4(rootDockerComposePath, existing + includeLine, "utf-8");
431
449
  logger.log(`Updated root docker-compose: ${rootDockerComposePath}`);
@@ -465,13 +483,34 @@ function formatError(err) {
465
483
  }
466
484
 
467
485
  // src/utils/platform-check.ts
468
- import { access } from "fs/promises";
486
+ import { access, readdir as readdir3, readFile as readFile5 } from "fs/promises";
469
487
  import { join as join9 } from "path";
470
488
  import { cwd } from "process";
489
+ async function findCoreDirName(dir) {
490
+ const entries = await readdir3(dir, { withFileTypes: true });
491
+ const coreEntry = entries.find((e) => e.isDirectory() && e.name.endsWith("-core"));
492
+ return coreEntry?.name ?? null;
493
+ }
494
+ async function readPlatformManifest(dir) {
495
+ const baseDir = dir ?? cwd();
496
+ const coreDirName = await findCoreDirName(baseDir);
497
+ if (!coreDirName) {
498
+ throw new Error("No *-core directory found \u2014 platform not initialized in this directory.");
499
+ }
500
+ const platformName = coreDirName.replace(/-core$/, "");
501
+ const pkgJson = JSON.parse(await readFile5(join9(baseDir, coreDirName, "package.json"), "utf-8"));
502
+ const scopeMatch = pkgJson.name.match(/^@([^/]+)\//);
503
+ if (!scopeMatch) {
504
+ throw new Error(`Could not parse organization from package name: "${pkgJson.name}"`);
505
+ }
506
+ return { platformName, organizationName: scopeMatch[1] };
507
+ }
471
508
  async function isPlatformInitialized() {
472
509
  try {
473
- await access(join9(cwd(), "core"));
474
- await access(join9(cwd(), "local"));
510
+ const coreDirName = await findCoreDirName(cwd());
511
+ if (!coreDirName) return false;
512
+ const platformName = coreDirName.replace(/-core$/, "");
513
+ await access(join9(cwd(), `${platformName}-local`));
475
514
  return true;
476
515
  } catch {
477
516
  return false;
@@ -499,10 +538,10 @@ async function createApplication(params, logger) {
499
538
  return;
500
539
  }
501
540
  const rootDir = cwd2();
502
- const applicationDir = join10(rootDir, applicationName);
503
- const bootstrapServiceDir = join10(applicationDir, "services", `${applicationName}-bootstrap-service`);
504
- const localDir = join10(rootDir, "local");
505
- logger.log(`Creating application monorepo "${applicationName}"...`);
541
+ const applicationDir = join10(rootDir, `${platformName}-${applicationName}`);
542
+ const bootstrapServiceDir = join10(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
543
+ const localDir = join10(rootDir, `${platformName}-local`);
544
+ logger.log(`Creating application monorepo "${platformName}-${applicationName}"...`);
506
545
  try {
507
546
  await scaffoldApplicationMonorepo(applicationDir, organizationName, platformName, applicationName, logger);
508
547
  } catch (err) {
@@ -511,10 +550,10 @@ async function createApplication(params, logger) {
511
550
  }
512
551
  await mkdir2(join10(applicationDir, "services"), { recursive: true });
513
552
  await mkdir2(join10(applicationDir, "ui"), { recursive: true });
514
- logger.log(`Creating bootstrap service "${applicationName}-bootstrap-service"...`);
515
- const bootstrapServiceDir_var = `${applicationName}/services`;
553
+ logger.log(`Creating bootstrap service "${platformName}-${applicationName}-bootstrap-service"...`);
554
+ const bootstrapServiceDir_var = `${platformName}-${applicationName}/services`;
516
555
  try {
517
- await scaffoldBootstrap(bootstrapServiceDir, organizationName, applicationName, bootstrapServiceDir_var, logger);
556
+ await scaffoldBootstrap(bootstrapServiceDir, organizationName, `${platformName}-${applicationName}`, bootstrapServiceDir_var, logger);
518
557
  } catch (err) {
519
558
  logger.log(`Error: Could not scaffold bootstrap service \u2014 ${formatError(err)}`);
520
559
  return;
@@ -530,7 +569,7 @@ async function createApplication(params, logger) {
530
569
  await addModuleEntry(
531
570
  bootstrapServiceDir,
532
571
  applicationName,
533
- buildUiModuleEntry(organizationName, applicationName, applicationDisplayName),
572
+ buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName),
534
573
  logger
535
574
  );
536
575
  }
@@ -538,13 +577,13 @@ async function createApplication(params, logger) {
538
577
  await addModuleEntry(
539
578
  bootstrapServiceDir,
540
579
  applicationName,
541
- buildServiceModuleEntry(organizationName, applicationName, applicationDisplayName),
580
+ buildServiceModuleEntry(organizationName, platformName, applicationName, applicationDisplayName),
542
581
  logger
543
582
  );
544
583
  }
545
584
  if (hasUserInterface) {
546
- const uiDir = join10(applicationDir, "ui", `${applicationName}-ui`);
547
- const uiBaseDir = `${applicationName}/ui`;
585
+ const uiDir = join10(applicationDir, "ui", `${platformName}-${applicationName}-ui`);
586
+ const uiBaseDir = `${platformName}-${applicationName}/ui`;
548
587
  try {
549
588
  await scaffoldUiModule(uiDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger);
550
589
  } catch (err) {
@@ -553,21 +592,22 @@ async function createApplication(params, logger) {
553
592
  }
554
593
  }
555
594
  if (hasBackendService) {
556
- const serviceDir = join10(applicationDir, "services", `${applicationName}-service`);
557
- const serviceBaseDir = `${applicationName}/services`;
595
+ const serviceDir = join10(applicationDir, "services", `${platformName}-${applicationName}-service`);
596
+ const serviceBaseDir = `${platformName}-${applicationName}/services`;
558
597
  try {
559
- await scaffoldNestjsService(serviceDir, organizationName, applicationName, applicationDisplayName, serviceBaseDir, logger);
598
+ await scaffoldNestjsService(serviceDir, organizationName, platformName, applicationName, applicationDisplayName, serviceBaseDir, logger);
560
599
  } catch (err) {
561
600
  logger.log(`Error: Could not scaffold NestJS service \u2014 ${formatError(err)}`);
562
601
  return;
563
602
  }
564
603
  }
565
- const dockerComposePath = join10(localDir, `${applicationName}-docker-compose.yml`);
604
+ const dockerComposePath = join10(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
566
605
  const basePort = await getNextAvailablePort(localDir);
567
606
  const uiPort = hasUserInterface ? basePort : 0;
568
607
  const servicePort = hasBackendService ? hasUserInterface ? basePort + 1 : basePort : 0;
569
608
  await createDockerCompose(
570
609
  dockerComposePath,
610
+ platformName,
571
611
  applicationName,
572
612
  hasUserInterface,
573
613
  hasBackendService,
@@ -576,8 +616,8 @@ async function createApplication(params, logger) {
576
616
  logger
577
617
  );
578
618
  const rootDockerComposePath = join10(localDir, "docker-compose.yml");
579
- await updateRootDockerCompose(rootDockerComposePath, applicationName, logger);
580
- logger.log(`Done! Application "${applicationName}" created at ${applicationDir}`);
619
+ await updateRootDockerCompose(rootDockerComposePath, platformName, applicationName, logger);
620
+ logger.log(`Done! Application "${platformName}-${applicationName}" created at ${applicationDir}`);
581
621
  }
582
622
 
583
623
  // src/commands/init/init.command.ts
@@ -630,31 +670,31 @@ async function scaffoldCustomizationUi(outputDir, variables, logger) {
630
670
 
631
671
  // src/commands/init/register-customization-module.ts
632
672
  import { join as join14 } from "path";
633
- import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
634
- async function registerCustomizationModule(bootstrapServiceDir, organizationName, logger) {
673
+ import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
674
+ async function registerCustomizationModule(bootstrapServiceDir, organizationName, platformName, logger) {
635
675
  const modulesJsonPath = join14(bootstrapServiceDir, "src", "data", "platform", "modules.json");
636
676
  const entry = {
637
- name: `@${organizationName}/platform-customization-ui`,
677
+ name: `@${organizationName}/${platformName}-customization-ui`,
638
678
  displayName: "Platform Customization UI",
639
679
  type: "app",
640
- baseUrl: "/platform-customization-ui",
641
- service: { host: "platform-customization-ui", port: 80 },
680
+ baseUrl: `/${platformName}-customization-ui`,
681
+ service: { host: `${platformName}-customization-ui`, port: 80 },
642
682
  ui: {
643
683
  route: "/",
644
- bundleFile: "platform-customization-ui.js",
684
+ bundleFile: `${platformName}-customization-ui.js`,
645
685
  isPlatformCustomization: true,
646
686
  customProps: {}
647
687
  },
648
688
  dependsOn: []
649
689
  };
650
- const existing = JSON.parse(await readFile5(modulesJsonPath, "utf-8"));
690
+ const existing = JSON.parse(await readFile6(modulesJsonPath, "utf-8"));
651
691
  existing.push(entry);
652
692
  await writeFile5(modulesJsonPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
653
693
  logger.log(`Registered customization module in ${modulesJsonPath}`);
654
694
  }
655
695
 
656
696
  // src/commands/init/generate-local-env.ts
657
- import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
697
+ import { readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
658
698
  import { join as join15 } from "path";
659
699
 
660
700
  // src/utils/random.ts
@@ -664,11 +704,11 @@ function generateRandomSecret() {
664
704
  }
665
705
 
666
706
  // src/commands/init/generate-local-env.ts
667
- async function generateLocalEnv(outputDir, logger) {
668
- const examplePath = join15(outputDir, "local", ".env.example");
669
- const envPath = join15(outputDir, "local", ".env");
670
- logger.log("Generating local/.env with random secrets...");
671
- const content = await readFile6(examplePath, "utf-8");
707
+ async function generateLocalEnv(outputDir, platformName, logger) {
708
+ const examplePath = join15(outputDir, `${platformName}-local`, ".env.example");
709
+ const envPath = join15(outputDir, `${platformName}-local`, ".env");
710
+ logger.log(`Generating ${platformName}-local/.env with random secrets...`);
711
+ const content = await readFile7(examplePath, "utf-8");
672
712
  const result = content.replace(/^(PAE_AUTH_JWT_SECRET|PAE_GATEWAY_SERVICE_ACCESS_SECRET|PAE_DB_PASSWORD)=$/gm, (_, key) => {
673
713
  return `${key}=${generateRandomSecret()}`;
674
714
  });
@@ -695,8 +735,8 @@ async function init(params, logger) {
695
735
  platformName,
696
736
  platformTitle,
697
737
  platformDisplayName,
698
- bootstrapName: "platform",
699
- bootstrapServiceDir: "core/services"
738
+ bootstrapName: platformName,
739
+ bootstrapServiceDir: `${platformName}-core/services`
700
740
  };
701
741
  try {
702
742
  await scaffoldPlatform(outputDir, variables, logger);
@@ -705,14 +745,14 @@ async function init(params, logger) {
705
745
  return;
706
746
  }
707
747
  try {
708
- await generateLocalEnv(outputDir, logger);
748
+ await generateLocalEnv(outputDir, platformName, logger);
709
749
  } catch (err) {
710
- logger.log(`Error: Could not generate local/.env \u2014 ${formatError(err)}`);
750
+ logger.log(`Error: Could not generate ${platformName}-local/.env \u2014 ${formatError(err)}`);
711
751
  return;
712
752
  }
713
753
  try {
714
754
  await scaffoldPlatformBootstrap(
715
- join16(outputDir, "core", "services", "platform-bootstrap-service"),
755
+ join16(outputDir, `${platformName}-core`, "services", `${platformName}-bootstrap-service`),
716
756
  variables,
717
757
  logger
718
758
  );
@@ -722,7 +762,7 @@ async function init(params, logger) {
722
762
  }
723
763
  try {
724
764
  await scaffoldCustomizationUi(
725
- join16(outputDir, "core", "ui", "platform-customization-ui"),
765
+ join16(outputDir, `${platformName}-core`, "ui", `${platformName}-customization-ui`),
726
766
  variables,
727
767
  logger
728
768
  );
@@ -732,8 +772,9 @@ async function init(params, logger) {
732
772
  }
733
773
  try {
734
774
  await registerCustomizationModule(
735
- join16(outputDir, "core", "services", "platform-bootstrap-service"),
775
+ join16(outputDir, `${platformName}-core`, "services", `${platformName}-bootstrap-service`),
736
776
  organizationName,
777
+ platformName,
737
778
  logger
738
779
  );
739
780
  } catch (err) {
@@ -749,11 +790,11 @@ import { cwd as cwd4 } from "process";
749
790
  import { fetch as undiciFetch, Agent } from "undici";
750
791
 
751
792
  // src/utils/env-reader.ts
752
- import { readFile as readFile7 } from "fs/promises";
793
+ import { readFile as readFile8 } from "fs/promises";
753
794
  async function readEnvFile(filePath) {
754
795
  let content;
755
796
  try {
756
- content = await readFile7(filePath, "utf-8");
797
+ content = await readFile8(filePath, "utf-8");
757
798
  } catch (error) {
758
799
  if (error.code === "ENOENT") {
759
800
  throw new Error(`.env file not found at ${filePath}`);
@@ -827,7 +868,8 @@ async function configureIdp(params, logger) {
827
868
  logger.log("Error: Cannot configure an IDP \u2014 no platform initialized in this directory.");
828
869
  return;
829
870
  }
830
- const envPath = join17(cwd4(), "local", ".env");
871
+ const { platformName } = await readPlatformManifest();
872
+ const envPath = join17(cwd4(), `${platformName}-local`, ".env");
831
873
  let env;
832
874
  try {
833
875
  env = await readEnvFile(envPath);
@@ -838,11 +880,11 @@ async function configureIdp(params, logger) {
838
880
  const gatewayUrl = env.get("PAE_GATEWAY_HOST_URL");
839
881
  const accessSecret = env.get("PAE_GATEWAY_SERVICE_ACCESS_SECRET");
840
882
  if (!gatewayUrl) {
841
- logger.log("Error: PAE_GATEWAY_HOST_URL is not set in local/.env");
883
+ logger.log(`Error: PAE_GATEWAY_HOST_URL is not set in ${platformName}-local/.env`);
842
884
  return;
843
885
  }
844
886
  if (!accessSecret) {
845
- logger.log("Error: PAE_GATEWAY_SERVICE_ACCESS_SECRET is not set in local/.env");
887
+ logger.log(`Error: PAE_GATEWAY_SERVICE_ACCESS_SECRET is not set in ${platformName}-local/.env`);
846
888
  return;
847
889
  }
848
890
  const provider = idpProviderRegistry.get(params.providerType);
@@ -881,7 +923,7 @@ async function configureIdp(params, logger) {
881
923
  // src/commands/create-service-module/create-service-module.command.ts
882
924
  import { join as join19 } from "path";
883
925
  import { cwd as cwd5 } from "process";
884
- import { access as access2, readFile as readFile9 } from "fs/promises";
926
+ import { access as access2 } from "fs/promises";
885
927
 
886
928
  // src/commands/create-service-module/scaffold-service-module.ts
887
929
  import { fileURLToPath as fileURLToPath9 } from "url";
@@ -921,12 +963,12 @@ function buildCustomServiceModuleEntry(organizationName, serviceName, serviceDis
921
963
  }
922
964
 
923
965
  // src/commands/create-service-module/append-docker-compose.ts
924
- import { readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
925
- async function appendServiceToDockerCompose(dockerComposePath, serviceName, applicationName, port, logger) {
966
+ import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
967
+ async function appendServiceToDockerCompose(dockerComposePath, serviceName, platformName, applicationName, port, logger) {
926
968
  const block = `
927
969
  ${serviceName}:
928
970
  build:
929
- context: ../${applicationName}/services/${serviceName}
971
+ context: ../${platformName}-${applicationName}/services/${serviceName}
930
972
  dockerfile: Dockerfile.development
931
973
  args:
932
974
  - BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
@@ -938,7 +980,7 @@ async function appendServiceToDockerCompose(dockerComposePath, serviceName, appl
938
980
  - \${PWD}/../:/app/out
939
981
  `;
940
982
  try {
941
- const existing = await readFile8(dockerComposePath, "utf-8");
983
+ const existing = await readFile9(dockerComposePath, "utf-8");
942
984
  await writeFile7(dockerComposePath, existing + block, "utf-8");
943
985
  logger.log(`Updated docker-compose: ${dockerComposePath}`);
944
986
  } catch (err) {
@@ -960,36 +1002,32 @@ async function createServiceModule(params, logger) {
960
1002
  return;
961
1003
  }
962
1004
  const rootDir = cwd5();
963
- const applicationDir = join19(rootDir, applicationName);
1005
+ let organizationName;
1006
+ let platformName;
1007
+ try {
1008
+ const manifest = await readPlatformManifest(rootDir);
1009
+ organizationName = manifest.organizationName;
1010
+ platformName = manifest.platformName;
1011
+ } catch (err) {
1012
+ logger.log(`Error: Could not read .platform.json \u2014 ${formatError(err)}`);
1013
+ return;
1014
+ }
1015
+ const applicationDir = join19(rootDir, `${platformName}-${applicationName}`);
964
1016
  try {
965
1017
  await access2(applicationDir);
966
1018
  } catch {
967
- logger.log(`Error: The specified application "${applicationName}" does not exist in the platform.`);
1019
+ logger.log(`Error: The specified application "${platformName}-${applicationName}" does not exist in the platform.`);
968
1020
  return;
969
1021
  }
970
- const fullServiceName = `${serviceName}-service`;
1022
+ const fullServiceName = `${platformName}-${serviceName}-service`;
971
1023
  const serviceDir = join19(applicationDir, "services", fullServiceName);
972
1024
  try {
973
1025
  await access2(serviceDir);
974
- logger.log(`Error: A service named "${fullServiceName}" already exists in application "${applicationName}".`);
1026
+ logger.log(`Error: A service named "${fullServiceName}" already exists in application "${platformName}-${applicationName}".`);
975
1027
  return;
976
1028
  } catch {
977
1029
  }
978
- let organizationName;
979
- try {
980
- const corePackageJson = JSON.parse(
981
- await readFile9(join19(rootDir, "core", "package.json"), "utf-8")
982
- );
983
- const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
984
- organizationName = scopeMatch?.[1];
985
- if (!organizationName) {
986
- throw new Error(`Could not parse organization from package name: "${corePackageJson.name}"`);
987
- }
988
- } catch (err) {
989
- logger.log(`Error: Could not read core/package.json \u2014 ${formatError(err)}`);
990
- return;
991
- }
992
- const serviceBaseDir = `${applicationName}/services`;
1030
+ const serviceBaseDir = `${platformName}-${applicationName}/services`;
993
1031
  try {
994
1032
  await scaffoldServiceModule(
995
1033
  serviceDir,
@@ -1003,28 +1041,28 @@ async function createServiceModule(params, logger) {
1003
1041
  logger.log(`Error: Could not scaffold NestJS service \u2014 ${formatError(err)}`);
1004
1042
  return;
1005
1043
  }
1006
- const bootstrapServiceDir = join19(applicationDir, "services", `${applicationName}-bootstrap-service`);
1044
+ const bootstrapServiceDir = join19(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
1007
1045
  const moduleEntry = buildCustomServiceModuleEntry(organizationName, fullServiceName, serviceDisplayName);
1008
1046
  await addModuleEntry(bootstrapServiceDir, applicationName, moduleEntry, logger);
1009
- const localDir = join19(rootDir, "local");
1010
- const dockerComposePath = join19(localDir, `${applicationName}-docker-compose.yml`);
1047
+ const localDir = join19(rootDir, `${platformName}-local`);
1048
+ const dockerComposePath = join19(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
1011
1049
  const port = await getNextAvailablePort(localDir);
1012
- await appendServiceToDockerCompose(dockerComposePath, fullServiceName, applicationName, port, logger);
1013
- logger.log(`Done! Service module "${fullServiceName}" added to application "${applicationName}".`);
1050
+ await appendServiceToDockerCompose(dockerComposePath, fullServiceName, platformName, applicationName, port, logger);
1051
+ logger.log(`Done! Service module "${fullServiceName}" added to application "${platformName}-${applicationName}".`);
1014
1052
  }
1015
1053
 
1016
1054
  // src/commands/create-ui-module/create-ui-module.command.ts
1017
1055
  import { join as join20 } from "path";
1018
1056
  import { cwd as cwd6 } from "process";
1019
- import { access as access3, readdir as readdir3, readFile as readFile11 } from "fs/promises";
1057
+ import { access as access3, readdir as readdir4 } from "fs/promises";
1020
1058
 
1021
1059
  // src/commands/create-ui-module/append-ui-docker-compose.ts
1022
1060
  import { readFile as readFile10, writeFile as writeFile8 } from "fs/promises";
1023
- async function appendUiToDockerCompose(dockerComposePath, applicationName, port, logger) {
1061
+ async function appendUiToDockerCompose(dockerComposePath, platformName, applicationName, port, logger) {
1024
1062
  const block = `
1025
- ${applicationName}-ui:
1063
+ ${platformName}-${applicationName}-ui:
1026
1064
  build:
1027
- context: ../${applicationName}/ui/${applicationName}-ui
1065
+ context: ../${platformName}-${applicationName}/ui/${platformName}-${applicationName}-ui
1028
1066
  dockerfile: Dockerfile.development
1029
1067
  ports:
1030
1068
  - ${port}:80
@@ -1054,56 +1092,49 @@ async function createUiModule(params, logger) {
1054
1092
  return;
1055
1093
  }
1056
1094
  const rootDir = cwd6();
1057
- const applicationDir = join20(rootDir, applicationName);
1095
+ let organizationName;
1096
+ let platformName;
1097
+ try {
1098
+ const manifest = await readPlatformManifest(rootDir);
1099
+ organizationName = manifest.organizationName;
1100
+ platformName = manifest.platformName;
1101
+ } catch (err) {
1102
+ logger.log(`Error: Could not read .platform.json \u2014 ${formatError(err)}`);
1103
+ return;
1104
+ }
1105
+ const applicationDir = join20(rootDir, `${platformName}-${applicationName}`);
1058
1106
  try {
1059
1107
  await access3(applicationDir);
1060
1108
  } catch {
1061
- logger.log(`Error: The specified application "${applicationName}" does not exist in the platform.`);
1109
+ logger.log(`Error: The specified application "${platformName}-${applicationName}" does not exist in the platform.`);
1062
1110
  return;
1063
1111
  }
1064
1112
  const uiDir = join20(applicationDir, "ui");
1065
1113
  try {
1066
- const uiEntries = await readdir3(uiDir);
1114
+ const uiEntries = await readdir4(uiDir);
1067
1115
  const existingUiModules = uiEntries.filter((e) => e !== ".gitkeep");
1068
1116
  if (existingUiModules.length > 0) {
1069
- logger.log(`Error: Currently we support only one UI module per application. Application "${applicationName}" already has a UI module.`);
1117
+ logger.log(`Error: Currently we support only one UI module per application. Application "${platformName}-${applicationName}" already has a UI module.`);
1070
1118
  return;
1071
1119
  }
1072
1120
  } catch {
1073
1121
  }
1074
- let organizationName;
1075
- let platformName;
1076
- try {
1077
- const corePackageJson = JSON.parse(
1078
- await readFile11(join20(rootDir, "core", "package.json"), "utf-8")
1079
- );
1080
- const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
1081
- organizationName = scopeMatch?.[1];
1082
- const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
1083
- platformName = rawName;
1084
- if (!organizationName || !platformName) {
1085
- throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
1086
- }
1087
- } catch (err) {
1088
- logger.log(`Error: Could not read core/package.json \u2014 ${formatError(err)}`);
1089
- return;
1090
- }
1091
- const uiOutputDir = join20(uiDir, `${applicationName}-ui`);
1092
- const uiBaseDir = `${applicationName}/ui`;
1122
+ const uiOutputDir = join20(uiDir, `${platformName}-${applicationName}-ui`);
1123
+ const uiBaseDir = `${platformName}-${applicationName}/ui`;
1093
1124
  try {
1094
1125
  await scaffoldUiModule(uiOutputDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger);
1095
1126
  } catch (err) {
1096
1127
  logger.log(`Error: Could not scaffold UI module \u2014 ${formatError(err)}`);
1097
1128
  return;
1098
1129
  }
1099
- const bootstrapServiceDir = join20(applicationDir, "services", `${applicationName}-bootstrap-service`);
1100
- const moduleEntry = buildUiModuleEntry(organizationName, applicationName, applicationDisplayName);
1130
+ const bootstrapServiceDir = join20(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
1131
+ const moduleEntry = buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName);
1101
1132
  await addModuleEntry(bootstrapServiceDir, applicationName, moduleEntry, logger);
1102
- const localDir = join20(rootDir, "local");
1103
- const dockerComposePath = join20(localDir, `${applicationName}-docker-compose.yml`);
1133
+ const localDir = join20(rootDir, `${platformName}-local`);
1134
+ const dockerComposePath = join20(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
1104
1135
  const port = await getNextAvailablePort(localDir);
1105
- await appendUiToDockerCompose(dockerComposePath, applicationName, port, logger);
1106
- logger.log(`Done! UI module "${applicationName}-ui" added to application "${applicationName}".`);
1136
+ await appendUiToDockerCompose(dockerComposePath, platformName, applicationName, port, logger);
1137
+ logger.log(`Done! UI module "${platformName}-${applicationName}-ui" added to application "${platformName}-${applicationName}".`);
1107
1138
  }
1108
1139
 
1109
1140
  // src/commands/registry.ts
@@ -1145,11 +1176,6 @@ var APP_STATE = {
1145
1176
  // src/hooks/use-command-runner.ts
1146
1177
  import { useState as useState2, useCallback, useRef } from "react";
1147
1178
 
1148
- // src/controllers/ui/create-application.ui-controller.ts
1149
- import { readFile as readFile12 } from "fs/promises";
1150
- import { join as join21 } from "path";
1151
- import { cwd as cwd7 } from "process";
1152
-
1153
1179
  // src/services/create-application.service.ts
1154
1180
  async function createApplicationService(params, logger) {
1155
1181
  await createApplication(params, logger);
@@ -1164,19 +1190,12 @@ async function createApplicationUiController(ctx) {
1164
1190
  let organizationName;
1165
1191
  let platformName;
1166
1192
  try {
1167
- const corePackageJson = JSON.parse(
1168
- await readFile12(join21(cwd7(), "core", "package.json"), "utf-8")
1169
- );
1170
- const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
1171
- organizationName = scopeMatch?.[1];
1172
- const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
1173
- platformName = rawName;
1174
- if (!organizationName || !platformName) {
1175
- throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
1176
- }
1193
+ const manifest = await readPlatformManifest();
1194
+ organizationName = manifest.organizationName;
1195
+ platformName = manifest.platformName;
1177
1196
  } catch (err) {
1178
1197
  const message = err instanceof Error ? err.message : String(err);
1179
- ctx.log(`Error: Could not read core/package.json \u2014 ${message}`);
1198
+ ctx.log(`Error: Could not read .platform.json \u2014 ${message}`);
1180
1199
  return;
1181
1200
  }
1182
1201
  const applicationName = await ctx.prompt("Application name:");
@@ -1247,7 +1266,7 @@ async function configureIdpUiController(ctx) {
1247
1266
  return;
1248
1267
  }
1249
1268
  const provider = providers[index];
1250
- const name = await ctx.prompt("Provider name:");
1269
+ const name = provider.type;
1251
1270
  const issuer = await ctx.prompt("Issuer URL:");
1252
1271
  const clientId = await ctx.prompt("Client ID:");
1253
1272
  const clientSecret = await ctx.prompt("Client Secret:");
@@ -1404,7 +1423,7 @@ function useCommandRunner({ appendStaticItem, setState }) {
1404
1423
  }
1405
1424
 
1406
1425
  // src/app.tsx
1407
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1426
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1408
1427
  var require2 = createRequire(import.meta.url);
1409
1428
  var { version } = require2("../package.json");
1410
1429
  function App() {
@@ -1491,17 +1510,17 @@ function App() {
1491
1510
  function renderActiveArea() {
1492
1511
  switch (state) {
1493
1512
  case APP_STATE.EXECUTING:
1494
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "row", gap: 1, children: [
1495
- /* @__PURE__ */ jsx6(Spinner, { label: "Running\u2026" }),
1496
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "(esc to cancel)" })
1513
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "row", gap: 1, children: [
1514
+ /* @__PURE__ */ jsx7(Spinner, { label: "Running\u2026" }),
1515
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "(esc to cancel)" })
1497
1516
  ] });
1498
1517
  case APP_STATE.PROMPTING:
1499
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
1500
- /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: promptMessage }),
1501
- /* @__PURE__ */ jsx6(Prompt, { value: promptValue, onChange: setPromptValue, onSubmit: handlePromptSubmit })
1518
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
1519
+ /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: promptMessage }),
1520
+ /* @__PURE__ */ jsx7(Prompt, { value: promptValue, onChange: setPromptValue, onSubmit: handlePromptSubmit })
1502
1521
  ] });
1503
1522
  default:
1504
- return /* @__PURE__ */ jsx6(
1523
+ return /* @__PURE__ */ jsx7(
1505
1524
  Prompt,
1506
1525
  {
1507
1526
  value: inputValue,
@@ -1514,17 +1533,14 @@ function App() {
1514
1533
  );
1515
1534
  }
1516
1535
  }
1517
- return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", children: [
1518
- /* @__PURE__ */ jsx6(ScrollbackHistory, { items: staticItems, version }),
1536
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
1537
+ /* @__PURE__ */ jsx7(ScrollbackHistory, { items: staticItems, version }),
1519
1538
  renderActiveArea(),
1520
- state === APP_STATE.PALETTE && /* @__PURE__ */ jsx6(CommandPalette, { commands: filteredCommands, selectedIndex })
1539
+ state === APP_STATE.PALETTE && /* @__PURE__ */ jsx7(CommandPalette, { commands: filteredCommands, selectedIndex })
1521
1540
  ] });
1522
1541
  }
1523
1542
 
1524
1543
  // src/controllers/cli/create-application.cli-controller.ts
1525
- import { readFile as readFile13 } from "fs/promises";
1526
- import { join as join22 } from "path";
1527
- import { cwd as cwd8 } from "process";
1528
1544
  async function createApplicationCliController(args2) {
1529
1545
  if (!await isPlatformInitialized()) {
1530
1546
  console.error("Error: Cannot create an application \u2014 no platform initialized in this directory.");
@@ -1548,19 +1564,12 @@ async function createApplicationCliController(args2) {
1548
1564
  let organizationName;
1549
1565
  let platformName;
1550
1566
  try {
1551
- const corePackageJson = JSON.parse(
1552
- await readFile13(join22(cwd8(), "core", "package.json"), "utf-8")
1553
- );
1554
- const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
1555
- organizationName = scopeMatch?.[1];
1556
- const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
1557
- platformName = rawName;
1558
- if (!organizationName || !platformName) {
1559
- throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
1560
- }
1567
+ const manifest = await readPlatformManifest();
1568
+ organizationName = manifest.organizationName;
1569
+ platformName = manifest.platformName;
1561
1570
  } catch (err) {
1562
1571
  const message = err instanceof Error ? err.message : String(err);
1563
- console.error(`Error: Could not read core/package.json \u2014 ${message}`);
1572
+ console.error(`Error: Could not read .platform.json \u2014 ${message}`);
1564
1573
  process.exit(1);
1565
1574
  }
1566
1575
  await createApplicationService(
@@ -1601,9 +1610,9 @@ async function configureIdpCliController(args2) {
1601
1610
  console.error("Error: Cannot configure an IDP \u2014 no platform initialized in this directory.");
1602
1611
  process.exit(1);
1603
1612
  }
1604
- const { providerType, name, issuer, clientId, clientSecret } = args2;
1605
- if (!providerType || !name || !issuer || !clientId || !clientSecret) {
1606
- logger.log("Error: Missing required arguments: providerType, name, issuer, clientId, clientSecret");
1613
+ const { providerType, issuer, clientId, clientSecret } = args2;
1614
+ if (!providerType || !issuer || !clientId || !clientSecret) {
1615
+ logger.log("Error: Missing required arguments: providerType, issuer, clientId, clientSecret");
1607
1616
  process.exit(1);
1608
1617
  }
1609
1618
  const provider = idpProviderRegistry.get(providerType);
@@ -1620,19 +1629,22 @@ async function configureIdpCliController(args2) {
1620
1629
  }
1621
1630
  extras[field.key] = value;
1622
1631
  }
1632
+ const name = providerType;
1623
1633
  await configureIdpService({ providerType, name, issuer, clientId, clientSecret, extras }, logger);
1624
1634
  }
1625
1635
 
1626
1636
  // src/utils/run-npm-script.ts
1627
1637
  import { spawn } from "child_process";
1628
1638
  import { access as access4 } from "fs/promises";
1629
- import { join as join23 } from "path";
1639
+ import { join as join21 } from "path";
1630
1640
  async function runNpmScript(scriptName, logger, signal) {
1631
- const localDir = join23(process.cwd(), "local");
1641
+ let localDir;
1632
1642
  try {
1643
+ const { platformName } = await readPlatformManifest();
1644
+ localDir = join21(process.cwd(), `${platformName}-local`);
1633
1645
  await access4(localDir);
1634
1646
  } catch {
1635
- logger.log(`Error: "local/" directory not found. Run "platform init" first.`);
1647
+ logger.log(`Error: No initialized platform found in this directory. Run "platform init" first.`);
1636
1648
  return;
1637
1649
  }
1638
1650
  return new Promise((resolve) => {
@@ -1812,10 +1824,10 @@ function parseKeyValueArgs(args2) {
1812
1824
  }
1813
1825
 
1814
1826
  // src/index.tsx
1815
- import { jsx as jsx7 } from "react/jsx-runtime";
1827
+ import { jsx as jsx8 } from "react/jsx-runtime";
1816
1828
  var args = process.argv.slice(2);
1817
1829
  if (args.length === 0) {
1818
- render(/* @__PURE__ */ jsx7(App, {}));
1830
+ render(/* @__PURE__ */ jsx8(App, {}));
1819
1831
  } else {
1820
1832
  const commandName = args[0];
1821
1833
  const params = parseKeyValueArgs(args.slice(1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluealba/platform-cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Blue Alba Platform CLI",
5
5
  "license": "PolyForm-Noncommercial-1.0.0",
6
6
  "type": "module",
@@ -8,10 +8,10 @@ ENV NAME=$NAME
8
8
  ARG DISPLAY_NAME
9
9
  ENV DISPLAY_NAME=$DISPLAY_NAME
10
10
 
11
- COPY ./ui/platform-customization-ui/caddy/Caddyfile /etc/caddy/Caddyfile
12
- COPY ./ui/platform-customization-ui/assets /usr/share/caddy/assets/
13
- COPY ./ui/platform-customization-ui/dist /usr/share/caddy/
14
- COPY ./ui/platform-customization-ui/CHANGELOG.md /usr/share/caddy/CHANGELOG.md
11
+ COPY ./ui/{{platformName}}-customization-ui/caddy/Caddyfile /etc/caddy/Caddyfile
12
+ COPY ./ui/{{platformName}}-customization-ui/assets /usr/share/caddy/assets/
13
+ COPY ./ui/{{platformName}}-customization-ui/dist /usr/share/caddy/
14
+ COPY ./ui/{{platformName}}-customization-ui/CHANGELOG.md /usr/share/caddy/CHANGELOG.md
15
15
 
16
16
 
17
17
  EXPOSE 8080
@@ -3,7 +3,7 @@ FROM node:20-alpine as development
3
3
  ENV NODE_ENV=development
4
4
  ENV PORT=80
5
5
 
6
- WORKDIR /app/out/core/ui/platform-customization-ui
6
+ WORKDIR /app/out/{{platformName}}-core/ui/{{platformName}}-customization-ui
7
7
 
8
8
  EXPOSE 80
9
9
 
@@ -1,9 +1,9 @@
1
1
  {
2
- "name": "@{{organizationName}}/platform-customization-ui",
2
+ "name": "@{{organizationName}}/{{platformName}}-customization-ui",
3
3
  "displayName": "Platform Customization UI",
4
4
  "version": "1.0.0",
5
- "main": "./distLib/platform-customization-ui.js",
6
- "types": "./distLib/platform-customization-ui.d.ts",
5
+ "main": "./distLib/{{platformName}}-customization-ui.js",
6
+ "types": "./distLib/{{platformName}}-customization-ui.d.ts",
7
7
  "files": [
8
8
  "distLib"
9
9
  ],
@@ -6,7 +6,7 @@
6
6
  "target": "ES6",
7
7
  "forceConsistentCasingInFileNames": true
8
8
  },
9
- "files": ["src/platform-customization-ui.tsx"],
9
+ "files": ["src/{{platformName}}-customization-ui.tsx"],
10
10
  "include": ["src/**/*"],
11
11
  "exclude": ["src/**/*.test*"]
12
12
  }
@@ -14,9 +14,9 @@ module.exports = (webpackConfigEnv, argv) => {
14
14
  });
15
15
 
16
16
  return merge(defaultConfig, {
17
- entry: './src/platform-customization-ui.tsx',
17
+ entry: './src/{{platformName}}-customization-ui.tsx',
18
18
  output: {
19
- filename: 'platform-customization-ui.js',
19
+ filename: '{{platformName}}-customization-ui.js',
20
20
  },
21
21
  // modify the webpack config however you'd like to by adding to this object
22
22
  externals: ['@bluealba/pae-ui-react-core'],
@@ -6,7 +6,7 @@ PAE_AUTH_JWT_SECRET=
6
6
  PAE_GATEWAY_SERVICE_ACCESS_SECRET=
7
7
  PAE_GATEWAY_URL=https://pae-nestjs-gateway-service:443
8
8
  PAE_GATEWAY_HOST_URL=https://localhost:443
9
- # PAE_FAVICON=/platform-customization-ui/assets/favicon.ico
9
+ # PAE_FAVICON=/{{platformName}}-customization-ui/assets/favicon.ico
10
10
 
11
11
  #
12
12
  # DB
@@ -0,0 +1,3 @@
1
+ include:
2
+ - path: ./{{platformName}}-core-docker-compose.yml
3
+ - path: ./platform-docker-compose.yml
@@ -7,10 +7,10 @@
7
7
  "scripts": {
8
8
  "install": "./scripts/install.sh",
9
9
  "build": "./scripts/build.sh",
10
- "start": "docker compose -p tradewinds-local -f docker-compose.yml up -d --build --remove-orphans --force-recreate",
11
- "stop": "docker compose -p tradewinds-local -f docker-compose.yml down",
10
+ "start": "docker compose -p {{platformName}}-local -f docker-compose.yml up -d --build --remove-orphans --force-recreate",
11
+ "stop": "docker compose -p {{platformName}}-local -f docker-compose.yml down",
12
12
  "restart": "npm run stop && npm run start",
13
- "destroy": "docker compose -p tradewinds-local -f docker-compose.yml down -v --rmi all"
13
+ "destroy": "docker compose -p {{platformName}}-local -f docker-compose.yml down -v --rmi all"
14
14
  },
15
15
  "engines": {
16
16
  "node": ">=20"
@@ -4,7 +4,7 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
4
4
 
5
5
  pids=()
6
6
  for dir in "$ROOT"/*/; do
7
- if [ "$dir" != "$ROOT/local/" ]; then
7
+ if [ "$dir" != "$ROOT/{{platformName}}-local/" ]; then
8
8
  echo "Building $dir..."
9
9
  (cd "$dir" && npm run build) &
10
10
  pids+=($!)
@@ -4,7 +4,7 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
4
4
 
5
5
  pids=()
6
6
  for dir in "$ROOT"/*/; do
7
- if [ "$dir" != "$ROOT/local/" ]; then
7
+ if [ "$dir" != "$ROOT/{{platformName}}-local/" ]; then
8
8
  echo "Installing $dir..."
9
9
  (cd "$dir" && npm i) &
10
10
  pids+=($!)
@@ -1,12 +1,12 @@
1
1
  # Core Services
2
2
  services:
3
- platform-bootstrap-service:
3
+ {{platformName}}-bootstrap-service:
4
4
  build:
5
- context: ../core/services/platform-bootstrap-service
5
+ context: ../{{platformName}}-core/services/{{platformName}}-bootstrap-service
6
6
  dockerfile: Dockerfile.development
7
7
  environment:
8
8
  - NODE_TLS_REJECT_UNAUTHORIZED=0
9
- - SERVICE_ACCESS_NAME=platform-bootstrap-service
9
+ - SERVICE_ACCESS_NAME={{platformName}}-bootstrap-service
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
- platform-customization-ui:
20
+ {{platformName}}-customization-ui:
21
21
  build:
22
- context: ../core/ui/platform-customization-ui
22
+ context: ../{{platformName}}-core/ui/{{platformName}}-customization-ui
23
23
  dockerfile: Dockerfile.development
24
24
  ports:
25
25
  - 9446:80
@@ -8,8 +8,8 @@ ENV NAME=$NAME
8
8
  ARG DISPLAY_NAME
9
9
  ENV DISPLAY_NAME=$DISPLAY_NAME
10
10
 
11
- COPY ./apps/{{applicationName}}-ui/version.json /usr/share/nginx/html/version.json
12
- COPY ./apps/{{applicationName}}-ui/dist /usr/share/caddy/
13
- COPY ./apps/{{applicationName}}-ui/caddy/Caddyfile /etc/caddy/Caddyfile
11
+ COPY ./apps/{{platformName}}-{{applicationName}}-ui/version.json /usr/share/nginx/html/version.json
12
+ COPY ./apps/{{platformName}}-{{applicationName}}-ui/dist /usr/share/caddy/
13
+ COPY ./apps/{{platformName}}-{{applicationName}}-ui/caddy/Caddyfile /etc/caddy/Caddyfile
14
14
 
15
15
  EXPOSE 8080
@@ -5,7 +5,7 @@ ENV PORT=80
5
5
 
6
6
  ARG BA_NPM_AUTH_TOKEN
7
7
 
8
- WORKDIR /app/out/{{uiBaseDir}}/{{applicationName}}-ui
8
+ WORKDIR /app/out/{{uiBaseDir}}/{{platformName}}-{{applicationName}}-ui
9
9
 
10
10
  EXPOSE 80
11
11
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@{{organizationName}}/{{applicationName}}-ui",
2
+ "name": "@{{organizationName}}/{{platformName}}-{{applicationName}}-ui",
3
3
  "version": "0.1.0",
4
4
  "displayName": "{{applicationDisplayName}}",
5
5
  "scripts": {
@@ -1,3 +0,0 @@
1
- include:
2
- - path: ./core-docker-compose.yml
3
- - path: ./platform-docker-compose.yml