@bluealba/platform-cli 1.0.1 → 1.1.0

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 (52) hide show
  1. package/dist/index.js +278 -15
  2. package/docs/404.mdx +5 -0
  3. package/docs/architecture/api-explorer.mdx +478 -0
  4. package/docs/architecture/architecture-diagrams.mdx +12 -0
  5. package/docs/architecture/authentication-system.mdx +903 -0
  6. package/docs/architecture/authorization-system.mdx +886 -0
  7. package/docs/architecture/bootstrap.mdx +1442 -0
  8. package/docs/architecture/gateway-architecture.mdx +845 -0
  9. package/docs/architecture/multi-tenancy.mdx +1150 -0
  10. package/docs/architecture/overview.mdx +776 -0
  11. package/docs/architecture/scheduler.mdx +818 -0
  12. package/docs/architecture/shell.mdx +885 -0
  13. package/docs/architecture/ui-extension-points.mdx +781 -0
  14. package/docs/architecture/user-states.mdx +794 -0
  15. package/docs/development/overview.mdx +21 -0
  16. package/docs/development/workflow.mdx +914 -0
  17. package/docs/getting-started/core-concepts.mdx +892 -0
  18. package/docs/getting-started/installation.mdx +780 -0
  19. package/docs/getting-started/overview.mdx +83 -0
  20. package/docs/getting-started/quick-start.mdx +940 -0
  21. package/docs/guides/adding-documentation-sites.mdx +1367 -0
  22. package/docs/guides/creating-services.mdx +1736 -0
  23. package/docs/guides/creating-ui-modules.mdx +1860 -0
  24. package/docs/guides/identity-providers.mdx +1007 -0
  25. package/docs/guides/mermaid-diagrams.mdx +212 -0
  26. package/docs/guides/using-feature-flags.mdx +1059 -0
  27. package/docs/guides/working-with-rooms.mdx +566 -0
  28. package/docs/index.mdx +57 -0
  29. package/docs/platform-cli/commands.mdx +604 -0
  30. package/docs/platform-cli/overview.mdx +195 -0
  31. package/package.json +5 -2
  32. package/skills/ba-platform/platform-cli.skill.md +26 -0
  33. package/skills/ba-platform/platform.skill.md +35 -0
  34. package/templates/application-monorepo-template/gitignore +95 -0
  35. package/templates/bootstrap-service-template/Dockerfile.development +1 -1
  36. package/templates/bootstrap-service-template/gitignore +57 -0
  37. package/templates/bootstrap-service-template/package.json +1 -1
  38. package/templates/bootstrap-service-template/src/main.ts +6 -16
  39. package/templates/customization-ui-module-template/Dockerfile.development +1 -1
  40. package/templates/customization-ui-module-template/gitignore +73 -0
  41. package/templates/nestjs-service-module-template/Dockerfile.development +1 -1
  42. package/templates/nestjs-service-module-template/gitignore +56 -0
  43. package/templates/platform-init-template/{{platformName}}-core/gitignore +97 -0
  44. package/templates/platform-init-template/{{platformName}}-core/local/.env.example +1 -1
  45. package/templates/platform-init-template/{{platformName}}-core/local/platform-docker-compose.yml +1 -1
  46. package/templates/platform-init-template/{{platformName}}-core/local/{{platformName}}-core-docker-compose.yml +0 -1
  47. package/templates/react-ui-module-template/Dockerfile +1 -1
  48. package/templates/react-ui-module-template/Dockerfile.development +1 -3
  49. package/templates/react-ui-module-template/caddy/Caddyfile +1 -1
  50. package/templates/react-ui-module-template/gitignore +72 -0
  51. package/templates/react-ui-module-template/Dockerfile_nginx +0 -11
  52. package/templates/react-ui-module-template/nginx/default.conf +0 -23
package/dist/index.js CHANGED
@@ -213,7 +213,7 @@ import { join as join2, dirname as dirname2 } from "path";
213
213
 
214
214
  // src/utils/template-engine.ts
215
215
  import { readdir, readFile, writeFile, mkdir, copyFile, stat, chmod } from "fs/promises";
216
- import { join, dirname, extname } from "path";
216
+ import { join, dirname, extname, basename } from "path";
217
217
  var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
218
218
  ".pem",
219
219
  ".crt",
@@ -239,6 +239,13 @@ function applyVariables(text, variables) {
239
239
  }
240
240
  return result;
241
241
  }
242
+ function transformFilename(relativePath) {
243
+ const base = basename(relativePath);
244
+ if (base === "gitignore") {
245
+ return join(dirname(relativePath), ".gitignore");
246
+ }
247
+ return relativePath;
248
+ }
242
249
  function isBinary(filePath) {
243
250
  return BINARY_EXTENSIONS.has(extname(filePath).toLowerCase());
244
251
  }
@@ -263,7 +270,7 @@ async function applyTemplate(config, onProgress) {
263
270
  const relativePath = srcPath.slice(templateDir4.length + 1);
264
271
  if (relativePath.endsWith(".gitkeep")) continue;
265
272
  if (exclude.includes(relativePath)) continue;
266
- const transformedRelative = applyVariables(relativePath, variables);
273
+ const transformedRelative = transformFilename(applyVariables(relativePath, variables));
267
274
  const destPath = join(outputDir, transformedRelative);
268
275
  await mkdir(dirname(destPath), { recursive: true });
269
276
  if (isBinary(srcPath)) {
@@ -453,7 +460,6 @@ function buildBootstrapBlock(platformName, applicationName) {
453
460
  - NODE_TLS_REJECT_UNAUTHORIZED=0
454
461
  - SERVICE_ACCESS_NAME=${applicationName}-bootstrap
455
462
  - WAIT_TIME=5000
456
- - SYNC_STRATEGY=\${PAE_BOOTSTRAP_SYNC_STRATEGY}
457
463
  - GATEWAY_SERVICE_URL=\${PAE_GATEWAY_URL}
458
464
  - SERVICE_ACCESS_SECRET=\${PAE_GATEWAY_SERVICE_ACCESS_SECRET}
459
465
  volumes:
@@ -481,8 +487,6 @@ function buildBackendBlock(platformName, applicationName, servicePort) {
481
487
  build:
482
488
  context: ../../${platformName}-${applicationName}/services/${serviceName}
483
489
  dockerfile: Dockerfile.development
484
- args:
485
- - BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
486
490
  ports:
487
491
  - ${servicePort}:80
488
492
  environment:
@@ -1120,8 +1124,6 @@ async function appendServiceToDockerCompose(dockerComposePath, serviceName, plat
1120
1124
  build:
1121
1125
  context: ../../${platformName}-${applicationName}/services/${serviceName}
1122
1126
  dockerfile: Dockerfile.development
1123
- args:
1124
- - BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
1125
1127
  ports:
1126
1128
  - ${port}:80
1127
1129
  environment:
@@ -1617,7 +1619,7 @@ async function installDependencies(layout, manifest, logger, signal, includeCore
1617
1619
  logger.log(`Installing dependencies in parallel: ${targets.map((t) => t.name).join(", ")}...`);
1618
1620
  await Promise.all(
1619
1621
  targets.map(
1620
- ({ name, dir }) => runCommand("npm", ["install"], dir, logger, signal).then(() => {
1622
+ ({ name, dir }) => runCommand("npm", ["install", "--prefer-offline"], dir, logger, signal).then(() => {
1621
1623
  logger.log(`\u2713 ${name} install done`);
1622
1624
  })
1623
1625
  )
@@ -2047,8 +2049,8 @@ async function checkIdpProviders(layout) {
2047
2049
  return { configured: false, providers: [], error: `gateway responded with ${response.status}` };
2048
2050
  }
2049
2051
  const data = await response.json();
2050
- const providers = data.map((p) => ({ name: p.name, type: p.type, active: p.active }));
2051
- return { configured: providers.length > 0, providers };
2052
+ const providers2 = data.map((p) => ({ name: p.name, type: p.type, active: p.active }));
2053
+ return { configured: providers2.length > 0, providers: providers2 };
2052
2054
  }
2053
2055
  async function gatherStatus() {
2054
2056
  const layout = await findPlatformLayout();
@@ -2268,6 +2270,91 @@ async function removePlatformAdmin(ruleId, logger) {
2268
2270
  return true;
2269
2271
  }
2270
2272
 
2273
+ // src/commands/install-ai-plugin/plugins/ba-platform/index.ts
2274
+ var baPlatformPlugin = {
2275
+ name: "ba-platform-plugin",
2276
+ description: "Blue Alba Platform knowledge and CLI skills for AI assistants",
2277
+ version: "1.0.0",
2278
+ skills: [
2279
+ {
2280
+ name: "platform",
2281
+ description: "Comprehensive Blue Alba Platform architecture and concepts knowledge",
2282
+ type: "skill",
2283
+ sourceFile: "skills/ba-platform/platform.skill.md"
2284
+ },
2285
+ {
2286
+ name: "platform-cli",
2287
+ description: "Blue Alba Platform CLI commands and usage knowledge",
2288
+ type: "skill",
2289
+ sourceFile: "skills/ba-platform/platform-cli.skill.md"
2290
+ }
2291
+ ]
2292
+ };
2293
+
2294
+ // src/commands/install-ai-plugin/plugins/registry.ts
2295
+ var pluginCatalog = [baPlatformPlugin];
2296
+ function findPlugin(name) {
2297
+ return pluginCatalog.find((p) => p.name === name);
2298
+ }
2299
+
2300
+ // src/commands/install-ai-plugin/install-ai-plugin.command.ts
2301
+ var INSTALL_AI_PLUGIN_COMMAND_NAME = "install-ai-plugin";
2302
+ var installAiPluginCommand = {
2303
+ name: INSTALL_AI_PLUGIN_COMMAND_NAME,
2304
+ description: "Install AI assistant plugins (skills, MCPs, hooks) for your AI provider"
2305
+ };
2306
+ async function installAiPlugin(params, context) {
2307
+ const { provider, docsSource, logger, confirmUpdate } = context;
2308
+ for (const pluginName of params.plugins) {
2309
+ const plugin = findPlugin(pluginName);
2310
+ if (!plugin) {
2311
+ logger.log(`Error: Plugin "${pluginName}" not found in catalog.`);
2312
+ continue;
2313
+ }
2314
+ const manifest = await provider.readManifest(pluginName);
2315
+ const diff = provider.calculateDiff(manifest, plugin);
2316
+ const hasStructuralChanges = diff.versionChanged || diff.newSkills.length > 0 || diff.removedSkills.length > 0;
2317
+ if (manifest && hasStructuralChanges) {
2318
+ logger.log(
2319
+ `Plugin "${pluginName}" is already installed (v${diff.currentVersion} \u2192 v${diff.targetVersion}).`
2320
+ );
2321
+ if (diff.newSkills.length > 0) {
2322
+ logger.log(` New skills: ${diff.newSkills.map((s) => s.name).join(", ")}`);
2323
+ }
2324
+ if (diff.removedSkills.length > 0) {
2325
+ logger.log(` Removed skills: ${diff.removedSkills.join(", ")}`);
2326
+ }
2327
+ if (diff.existingSkills.length > 0) {
2328
+ logger.log(` Updated skills: ${diff.existingSkills.map((s) => s.name).join(", ")}`);
2329
+ }
2330
+ if (!params.force && confirmUpdate) {
2331
+ const proceed = await confirmUpdate(diff, plugin);
2332
+ if (!proceed) {
2333
+ logger.log(`Skipped "${pluginName}".`);
2334
+ continue;
2335
+ }
2336
+ }
2337
+ for (const skillName of diff.removedSkills) {
2338
+ await provider.removeSkill(skillName, logger);
2339
+ }
2340
+ } else if (!manifest) {
2341
+ logger.log(`Installing plugin "${pluginName}" v${plugin.version}...`);
2342
+ }
2343
+ for (const skill of plugin.skills) {
2344
+ await provider.installSkill(skill, docsSource, logger);
2345
+ }
2346
+ await provider.writeManifest({
2347
+ plugin: pluginName,
2348
+ version: plugin.version,
2349
+ provider: provider.name,
2350
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
2351
+ skills: plugin.skills.map((s) => s.name)
2352
+ });
2353
+ await provider.updatePermissions(docsSource, logger);
2354
+ logger.log(`Plugin "${pluginName}" v${plugin.version} installed successfully.`);
2355
+ }
2356
+ }
2357
+
2271
2358
  // src/commands/registry.ts
2272
2359
  var CommandRegistry = class {
2273
2360
  commands = /* @__PURE__ */ new Map();
@@ -2308,6 +2395,7 @@ for (const cmd of localScriptCommands) {
2308
2395
  }
2309
2396
  registry.register(statusCommand);
2310
2397
  registry.register(managePlatformAdminsCommand);
2398
+ registry.register(installAiPluginCommand);
2311
2399
 
2312
2400
  // src/app-state.ts
2313
2401
  var APP_STATE = {
@@ -2405,12 +2493,12 @@ async function configureIdpUiController(ctx) {
2405
2493
  ctx.log("Error: Cannot configure an IDP \u2014 no platform initialized in this directory.");
2406
2494
  return;
2407
2495
  }
2408
- const providers = getAllProviders();
2496
+ const providers2 = getAllProviders();
2409
2497
  const providerType = await ctx.select(
2410
2498
  "Select IDP type:",
2411
- providers.map((p) => ({ label: p.displayName, value: p.type }))
2499
+ providers2.map((p) => ({ label: p.displayName, value: p.type }))
2412
2500
  );
2413
- const provider = providers.find((p) => p.type === providerType);
2501
+ const provider = providers2.find((p) => p.type === providerType);
2414
2502
  const name = await ctx.prompt("Provider name:");
2415
2503
  const issuer = await ctx.prompt("Issuer URL:");
2416
2504
  const clientId = await ctx.prompt("Client ID:");
@@ -2819,6 +2907,153 @@ async function handleRemove(ctx) {
2819
2907
  ctx.log(`Successfully removed ${successCount} of ${selected.length} admin(s).`);
2820
2908
  }
2821
2909
 
2910
+ // src/services/install-ai-plugin.service.ts
2911
+ async function installAiPluginService(params, context) {
2912
+ await installAiPlugin(params, context);
2913
+ }
2914
+
2915
+ // src/commands/install-ai-plugin/providers/claude.provider.ts
2916
+ import { homedir as homedir2 } from "os";
2917
+ import { join as join26 } from "path";
2918
+ import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir3, rm } from "fs/promises";
2919
+ var ClaudeProvider = class {
2920
+ name = "claude";
2921
+ baseDir = join26(homedir2(), ".claude");
2922
+ getInstallPath(skillName) {
2923
+ return join26(this.baseDir, "skills", skillName, "SKILL.md");
2924
+ }
2925
+ manifestPath(pluginName) {
2926
+ return join26(this.baseDir, `${pluginName}.manifest.json`);
2927
+ }
2928
+ async readManifest(pluginName) {
2929
+ try {
2930
+ const content = await readFile10(this.manifestPath(pluginName), "utf-8");
2931
+ return JSON.parse(content);
2932
+ } catch {
2933
+ return null;
2934
+ }
2935
+ }
2936
+ async writeManifest(manifest) {
2937
+ await mkdir3(this.baseDir, { recursive: true });
2938
+ await writeFile9(
2939
+ this.manifestPath(manifest.plugin),
2940
+ JSON.stringify(manifest, null, 2),
2941
+ "utf-8"
2942
+ );
2943
+ }
2944
+ calculateDiff(manifest, plugin) {
2945
+ const installedSkills = manifest?.skills ?? [];
2946
+ const targetSkillNames = plugin.skills.map((s) => s.name);
2947
+ return {
2948
+ newSkills: plugin.skills.filter((s) => !installedSkills.includes(s.name)),
2949
+ removedSkills: installedSkills.filter((name) => !targetSkillNames.includes(name)),
2950
+ existingSkills: plugin.skills.filter((s) => installedSkills.includes(s.name)),
2951
+ versionChanged: manifest?.version !== plugin.version,
2952
+ currentVersion: manifest?.version ?? null,
2953
+ targetVersion: plugin.version
2954
+ };
2955
+ }
2956
+ async installSkill(skill, docsSource, logger) {
2957
+ const sourcePath = docsSource.resolve(skill.sourceFile);
2958
+ let content = await readFile10(sourcePath, "utf-8");
2959
+ const docsPath = docsSource.resolve("docs");
2960
+ content = content.replaceAll("{{docsPath}}", docsPath);
2961
+ const installPath = this.getInstallPath(skill.name);
2962
+ await mkdir3(join26(installPath, ".."), { recursive: true });
2963
+ await writeFile9(installPath, content, "utf-8");
2964
+ logger.log(` Installed skill: ${installPath}`);
2965
+ }
2966
+ async removeSkill(skillName, logger) {
2967
+ const skillDir = join26(this.baseDir, "skills", skillName);
2968
+ try {
2969
+ await rm(skillDir, { recursive: true, force: true });
2970
+ logger.log(` Removed skill: ${skillDir}`);
2971
+ } catch {
2972
+ }
2973
+ }
2974
+ async updatePermissions(docsSource, logger) {
2975
+ const settingsPath = join26(this.baseDir, "settings.json");
2976
+ const docsPath = docsSource.resolve("docs");
2977
+ let settings = {};
2978
+ try {
2979
+ const content = await readFile10(settingsPath, "utf-8");
2980
+ settings = JSON.parse(content);
2981
+ } catch {
2982
+ }
2983
+ const permissions = settings.permissions ?? {};
2984
+ const additionalDirectories = permissions.additionalDirectories ?? [];
2985
+ if (additionalDirectories.includes(docsPath)) {
2986
+ return;
2987
+ }
2988
+ permissions.additionalDirectories = [...additionalDirectories, docsPath];
2989
+ settings.permissions = permissions;
2990
+ await mkdir3(this.baseDir, { recursive: true });
2991
+ await writeFile9(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
2992
+ logger.log(` Granted read access to docs: ${docsPath}`);
2993
+ }
2994
+ };
2995
+
2996
+ // src/commands/install-ai-plugin/providers/index.ts
2997
+ var providers = {
2998
+ claude: () => new ClaudeProvider()
2999
+ };
3000
+ var providerNames = Object.keys(providers);
3001
+ function getProvider(name) {
3002
+ const factory = providers[name];
3003
+ if (!factory) {
3004
+ throw new Error(`Unknown AI provider: "${name}". Available: ${providerNames.join(", ")}`);
3005
+ }
3006
+ return factory();
3007
+ }
3008
+
3009
+ // src/commands/install-ai-plugin/docs-source/local.docs-source.ts
3010
+ import { fileURLToPath as fileURLToPath10 } from "url";
3011
+ import { join as join27, dirname as dirname12 } from "path";
3012
+ var packageRoot = join27(dirname12(fileURLToPath10(import.meta.url)), "..");
3013
+ var LocalDocsSource = class {
3014
+ resolve(relativePath) {
3015
+ return join27(packageRoot, relativePath);
3016
+ }
3017
+ };
3018
+
3019
+ // src/controllers/ui/install-ai-plugin.ui-controller.ts
3020
+ async function installAiPluginUiController(ctx) {
3021
+ const providerName = await ctx.select(
3022
+ "Select AI provider:",
3023
+ providerNames.map((name) => ({
3024
+ label: name.charAt(0).toUpperCase() + name.slice(1),
3025
+ value: name
3026
+ }))
3027
+ );
3028
+ const selectedPlugins = await ctx.multiselect(
3029
+ "Select plugins to install:",
3030
+ pluginCatalog.map((p) => ({
3031
+ label: `${p.name} \u2014 ${p.description}`,
3032
+ value: p.name
3033
+ }))
3034
+ );
3035
+ if (selectedPlugins.length === 0) {
3036
+ ctx.log("No plugins selected.");
3037
+ return;
3038
+ }
3039
+ const provider = getProvider(providerName);
3040
+ const docsSource = new LocalDocsSource();
3041
+ await installAiPluginService(
3042
+ { provider: providerName, plugins: selectedPlugins },
3043
+ {
3044
+ provider,
3045
+ docsSource,
3046
+ logger: ctx,
3047
+ confirmUpdate: async (diff, plugin) => {
3048
+ return ctx.confirm(
3049
+ `Update "${plugin.name}" from v${diff.currentVersion} to v${diff.targetVersion}?`,
3050
+ true
3051
+ );
3052
+ }
3053
+ }
3054
+ );
3055
+ }
3056
+
2822
3057
  // src/controllers/ui/registry.ts
2823
3058
  var uiControllers = /* @__PURE__ */ new Map([
2824
3059
  [CREATE_APPLICATION_COMMAND_NAME, createApplicationUiController],
@@ -2832,7 +3067,8 @@ var uiControllers = /* @__PURE__ */ new Map([
2832
3067
  [START_COMMAND_NAME, createLocalScriptUiController(START_COMMAND_NAME)],
2833
3068
  [STOP_COMMAND_NAME, createLocalScriptUiController(STOP_COMMAND_NAME)],
2834
3069
  [DESTROY_COMMAND_NAME, createLocalScriptUiController(DESTROY_COMMAND_NAME)],
2835
- [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsUiController]
3070
+ [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsUiController],
3071
+ [INSTALL_AI_PLUGIN_COMMAND_NAME, installAiPluginUiController]
2836
3072
  ]);
2837
3073
 
2838
3074
  // src/hooks/use-command-runner.ts
@@ -3463,6 +3699,32 @@ async function managePlatformAdminsCliController(args2) {
3463
3699
  }
3464
3700
  }
3465
3701
 
3702
+ // src/controllers/cli/install-ai-plugin.cli-controller.ts
3703
+ async function installAiPluginCliController(args2) {
3704
+ const { provider: providerName, plugins: pluginsArg, force } = args2;
3705
+ if (!providerName) {
3706
+ console.error('Error: "provider" argument is required (e.g., provider=claude).');
3707
+ process.exit(1);
3708
+ }
3709
+ if (!pluginsArg) {
3710
+ console.error(
3711
+ 'Error: "plugins" argument is required (e.g., plugins=ba-platform-plugin).'
3712
+ );
3713
+ process.exit(1);
3714
+ }
3715
+ const plugins = pluginsArg.split(",").map((s) => s.trim());
3716
+ const provider = getProvider(providerName);
3717
+ const docsSource = new LocalDocsSource();
3718
+ await installAiPluginService(
3719
+ { provider: providerName, plugins, force: force === "true" },
3720
+ {
3721
+ provider,
3722
+ docsSource,
3723
+ logger: { log: console.log }
3724
+ }
3725
+ );
3726
+ }
3727
+
3466
3728
  // src/controllers/cli/registry.ts
3467
3729
  var cliControllers = /* @__PURE__ */ new Map([
3468
3730
  [CREATE_APPLICATION_COMMAND_NAME, createApplicationCliController],
@@ -3476,7 +3738,8 @@ var cliControllers = /* @__PURE__ */ new Map([
3476
3738
  [START_COMMAND_NAME, createLocalScriptCliController(START_COMMAND_NAME)],
3477
3739
  [STOP_COMMAND_NAME, createLocalScriptCliController(STOP_COMMAND_NAME)],
3478
3740
  [DESTROY_COMMAND_NAME, createLocalScriptCliController(DESTROY_COMMAND_NAME)],
3479
- [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsCliController]
3741
+ [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsCliController],
3742
+ [INSTALL_AI_PLUGIN_COMMAND_NAME, installAiPluginCliController]
3480
3743
  ]);
3481
3744
 
3482
3745
  // src/utils/parse-args.ts
package/docs/404.mdx ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Page Not Found
3
+ ---
4
+
5
+ Sorry, this page doesn't exist. Use the navigation to find what you're looking for.