@aifabrix/builder 2.36.2 → 2.37.5

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 (43) hide show
  1. package/.cursor/rules/project-rules.mdc +19 -0
  2. package/README.md +68 -104
  3. package/integration/hubspot/test.js +1 -1
  4. package/lib/api/wizard.api.js +24 -1
  5. package/lib/app/deploy.js +43 -7
  6. package/lib/app/display.js +1 -1
  7. package/lib/app/list.js +3 -1
  8. package/lib/app/run-helpers.js +1 -1
  9. package/lib/build/index.js +3 -4
  10. package/lib/cli/index.js +45 -0
  11. package/lib/cli/setup-app.js +230 -0
  12. package/lib/cli/setup-auth.js +88 -0
  13. package/lib/cli/setup-dev.js +101 -0
  14. package/lib/cli/setup-environment.js +53 -0
  15. package/lib/cli/setup-external-system.js +87 -0
  16. package/lib/cli/setup-infra.js +219 -0
  17. package/lib/cli/setup-secrets.js +48 -0
  18. package/lib/cli/setup-utility.js +202 -0
  19. package/lib/cli.js +7 -961
  20. package/lib/commands/up-common.js +31 -1
  21. package/lib/commands/up-miso.js +6 -2
  22. package/lib/commands/wizard-core.js +32 -7
  23. package/lib/core/config.js +10 -0
  24. package/lib/core/ensure-encryption-key.js +56 -0
  25. package/lib/deployment/deployer-status.js +101 -0
  26. package/lib/deployment/deployer.js +62 -110
  27. package/lib/deployment/environment.js +133 -34
  28. package/lib/external-system/deploy.js +5 -1
  29. package/lib/external-system/test-auth.js +14 -7
  30. package/lib/generator/wizard.js +37 -41
  31. package/lib/infrastructure/helpers.js +1 -1
  32. package/lib/schema/environment-deploy-request.schema.json +64 -0
  33. package/lib/utils/help-builder.js +5 -2
  34. package/lib/utils/paths.js +22 -4
  35. package/lib/utils/secrets-generator.js +23 -8
  36. package/lib/utils/secrets-helpers.js +46 -21
  37. package/package.json +1 -1
  38. package/scripts/install-local.js +11 -2
  39. package/templates/applications/README.md.hbs +3 -3
  40. package/templates/applications/dataplane/variables.yaml +0 -2
  41. package/templates/applications/miso-controller/variables.yaml +0 -2
  42. package/templates/external-system/deploy.js.hbs +69 -0
  43. package/templates/infra/environment-dev.json +10 -0
@@ -70,6 +70,23 @@ lib/
70
70
  └── schema/ # JSON schemas
71
71
  ```
72
72
 
73
+ ### Generated Output (integration/ and builder/)
74
+
75
+ Files under **integration/** and **builder/** are **auto-generated** by the CLI. When fixing bugs or changing behavior, validate **where** each file is produced so fixes go into the generator, not only into the generated artifact.
76
+
77
+ - **integration/** – External system / wizard output:
78
+ - Path: `integration/<appName>/` (see `lib/utils/paths.js` → `getIntegrationPath`).
79
+ - Generated by: `lib/generator/wizard.js` (`generateWizardFiles`, `generateConfigFilesForWizard`), `lib/external-system/download.js`, wizard commands in `lib/commands/wizard-core.js` and `lib/commands/wizard.js`.
80
+ - Typical outputs: `variables.yaml`, `env.template`, `README.md`, `*-system.json`, `*-datasource*.json`, `*-deploy.json`, deploy script (`deploy.js`), and optionally `wizard.yaml`, `error.log`.
81
+ - **builder/** – Application (non-external) output:
82
+ - Path: `builder/<appName>/` or custom root via `AIFABRIX_BUILDER_DIR` (see `lib/utils/paths.js` → `getBuilderPath`).
83
+ - Generated by: app create/register flow, `lib/generator/index.js`, `lib/commands/up-common.js`, `lib/core/secrets.js`, and related app/deploy logic.
84
+ - Typical outputs: `variables.yaml`, `env.template`, deploy JSON, `.env` (from secrets), and app-specific config.
85
+
86
+ **Editable vs generated:**
87
+ - Some generated files are **intended to be edited** (e.g. `variables.yaml`, `env.template`, `README.md`, `wizard.yaml`). Improvements to defaults or structure still belong in the generator/templates.
88
+ - **When debugging:** First identify the **source of generation** (which module and function write the file). Fix bugs in that generator or template; avoid treating a one-off edit in integration/ or builder/ as the permanent fix unless it’s a deliberate local override.
89
+
73
90
  ### CLI Command Pattern
74
91
  Commands are defined in `lib/cli.js` using Commander.js:
75
92
  ```javascript
@@ -850,6 +867,7 @@ Define request/response types using JSDoc `@typedef`:
850
867
 
851
868
  ### Must Do (✅)
852
869
  - ✅ Validate all inputs (app names, file paths, URLs)
870
+ - ✅ When fixing bugs in integration/ or builder/ output: identify the generator that produces the file and fix the source (lib/generator, lib/commands, templates), not only the generated artifact
853
871
  - ✅ Use try-catch for all async operations
854
872
  - ✅ Provide meaningful error messages with context
855
873
  - ✅ Use JSDoc for all public functions
@@ -874,6 +892,7 @@ Define request/response types using JSDoc `@typedef`:
874
892
  - ❌ Never use `eval()` or `Function()` constructor
875
893
  - ❌ Never use raw paths (always use path.join)
876
894
  - ❌ Never make direct API calls using `makeApiCall` in new code (use `lib/api/` modules)
895
+ - ❌ Never treat one-off edits in integration/ or builder/ as the permanent fix for a bug—update the generator or template that produces the file
877
896
  - ❌ Never skip type definitions for API request/response types
878
897
  - ❌ Never log authentication tokens or secrets in API calls
879
898
 
package/README.md CHANGED
@@ -1,9 +1,13 @@
1
- # AI Fabrix - Builder SDK
1
+ # AI Fabrix - Builder
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@aifabrix/builder.svg)](https://www.npmjs.com/package/@aifabrix/builder)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Local development infrastructure + Azure deployment tool.
6
+ Install the AI Fabrix platform and test it locally. Then add external integrations or build your own applications.
7
+
8
+ ← **Full documentation:** [docs/README.md](docs/README.md) (table of contents for all guides)
9
+
10
+ ---
7
11
 
8
12
  ## Install
9
13
 
@@ -11,126 +15,86 @@ Local development infrastructure + Azure deployment tool.
11
15
  npm install -g @aifabrix/builder
12
16
  ```
13
17
 
14
- ## Quick Start
18
+ **Alias:** You can use `aifx` instead of `aifabrix` in any command.
15
19
 
16
- ```bash
17
- aifabrix up # Start Postgres + Redis
18
- aifabrix create myapp # Create your app
19
- aifabrix build myapp # Build Docker image
20
- aifabrix run myapp # Run locally
21
- # Stop the app (optionally remove its data volume)
22
- aifabrix down myapp
23
- # aifabrix down myapp --volumes
24
- ```
20
+ ---
25
21
 
26
- [Full Guide](docs/quick-start.md) | [CLI Commands](docs/cli-reference.md)
22
+ ## Goal 1: Start and test the AI Fabrix platform
27
23
 
28
- ## What You Get
24
+ Get the platform running locally so you can try it.
29
25
 
30
- - **Local Postgres + Redis infrastructure** - Runs in Docker
31
- - **Auto-generated Dockerfiles** - TypeScript and Python templates
32
- - **Environment variable management** - Secret resolution with kv:// references
33
- - **Azure deployment pipeline** - Push to ACR and deploy via controller
26
+ 1. **Start local infrastructure** (Postgres, Redis, optional Traefik):
34
27
 
35
- ## Optional Platform Apps
28
+ ```bash
29
+ aifabrix up-infra
30
+ ```
36
31
 
37
- Want authentication or deployment controller?
32
+ 2. **Start the platform** (Keycloak, Miso Controller, Dataplane) from community images:
38
33
 
39
- **Quick install from images (no build):**
40
- ```bash
41
- aifabrix up # Start Postgres + Redis first
42
- aifabrix up-miso # Install Keycloak + Miso Controller from images (auto-generated secrets for testing)
43
- ```
34
+ ```bash
35
+ aifabrix up-platform
36
+ ```
44
37
 
45
- **Or create and build from templates:**
46
- ```bash
47
- # Keycloak for authentication
48
- aifabrix create keycloak --port 8082 --database --template keycloak
49
- aifabrix build keycloak
50
- aifabrix run keycloak
51
-
52
- # Miso Controller for Azure deployments
53
- aifabrix create miso-controller --port 3000 --database --redis --template miso-controller
54
- aifabrix build miso-controller
55
- aifabrix run miso-controller
56
- ```
38
+ Or run platform apps separately: `aifabrix up-miso` then `aifabrix up-dataplane`. Infra must be up first.
57
39
 
58
- **Dataplane in dev (after login):**
59
- ```bash
60
- aifabrix login --environment dev
61
- aifabrix up-dataplane # Register or rotate, run, and deploy dataplane in dev
62
- ```
40
+ 3. **Configure secrets** You need either **OpenAI** or **Azure OpenAI**:
41
+
42
+ - **OpenAI:** set your API key:
43
+ ```bash
44
+ aifabrix secrets set secrets-openaiApiKeyVault <your-openai-secret-key>
45
+ ```
46
+ - **Azure OpenAI:** set endpoint and API key:
47
+ ```bash
48
+ aifabrix secrets set azure-openaiapi-urlKeyVault <your-azure-openai-endpoint-url>
49
+ aifabrix secrets set secrets-azureOpenaiApiKeyVault <your-azure-openai-secret-key>
50
+ ```
51
+
52
+ Secrets are stored in `~/.aifabrix/secrets.local.yaml` or the file from `aifabrix-secrets` in your config (e.g. `builder/secrets.local.yaml`).
53
+
54
+ → [Infrastructure guide](docs/infrastructure.md)
63
55
 
64
- → [Infrastructure Guide](docs/infrastructure.md)
56
+ ---
57
+
58
+ ## Goal 2: External system integration
59
+
60
+ Create and deploy an external system (e.g. HubSpot): wizard or manual setup, then validate and deploy.
61
+
62
+ **Example: HubSpot**
63
+
64
+ - Create: `aifabrix create hubspot-test --type external` (or `aifabrix wizard` for guided setup).
65
+ - Configure auth and datasources under `integration/hubspot-test/`.
66
+ - Validate: `aifabrix validate hubspot-test`
67
+ - Deploy: `aifabrix deploy hubspot-test`
68
+
69
+ → [External systems guide](docs/external-systems.md) · [Wizard](docs/wizard.md)
70
+
71
+ ---
72
+
73
+ ## Goal 3: Build your own application
74
+
75
+ Create, configure, and run your own AI Fabrix application locally or deploy it (create app → configure → build → run / deploy).
76
+
77
+ → [Your own applications](docs/your-own-applications.md)
78
+
79
+ ---
65
80
 
66
81
  ## Documentation
67
82
 
68
- - [Quick Start](docs/quick-start.md) - Get running in 5 minutes
69
- - [Infrastructure](docs/infrastructure.md) - What runs and why
70
- - [Configuration](docs/configuration.md) - Config file reference
71
- - [Building](docs/building.md) - Build process explained
72
- - [Running](docs/running.md) - Run apps locally
73
- - [Deploying](docs/deploying.md) - Deploy to Azure
74
- - [CLI Reference](docs/cli-reference.md) - All commands
75
-
76
- ## How It Works
77
-
78
- 1. **Infrastructure** - Minimal baseline (Postgres + Redis)
79
- 2. **Create** - Generate config files for your app
80
- 3. **Build** - Auto-detect runtime and build Docker image
81
- 4. **Run** - Start locally, connected to infrastructure
82
- 5. **Deploy** - Push to ACR and deploy via controller
83
-
84
- ```mermaid
85
- %%{init: {
86
- "theme": "base",
87
- "themeVariables": {
88
- "fontFamily": "Poppins, Arial Rounded MT Bold, Arial, sans-serif",
89
- "fontSize": "16px",
90
- "background": "#FFFFFF",
91
- "primaryColor": "#F8FAFC",
92
- "primaryTextColor": "#0B0E15",
93
- "primaryBorderColor": "#E2E8F0",
94
- "lineColor": "#E2E8F0",
95
- "textColor": "#0B0E15",
96
- "borderRadius": 16
97
- },
98
- "flowchart": {
99
- "curve": "linear",
100
- "nodeSpacing": 34,
101
- "rankSpacing": 34,
102
- "padding": 10
103
- }
104
- }}%%
105
-
106
- flowchart TD
107
-
108
- %% =======================
109
- %% Styles
110
- %% =======================
111
- classDef base fill:#FFFFFF,color:#0B0E15,stroke:#E2E8F0,stroke-width:1.5px;
112
- classDef primary fill:#0062FF,color:#ffffff,stroke-width:0px;
113
-
114
- %% =======================
115
- %% Flow
116
- %% =======================
117
- Install[Install CLI]:::primary --> Up[Start Infrastructure]:::base
118
- Up --> Create[Create App]:::base
119
- Create --> Build[Build Image]:::base
120
- Build --> Run[Run Locally]:::base
121
- Run --> Deploy[Deploy to Azure]:::primary
122
- ```
83
+ All guides and references are listed in **[docs/README.md](docs/README.md)** (table of contents).
123
84
 
124
- ## Development
85
+ - [CLI Reference](docs/cli-reference.md) – All commands
86
+ - [Infrastructure](docs/infrastructure.md) – What runs and why
87
+ - [Configuration](docs/configuration.md) – Config files
125
88
 
126
- - **Tests**: `npm test` (runs via wrapper; handles known Jest/Node exit issues).
127
- - **Coverage**: `npm run test:coverage` — runs tests with coverage through the same wrapper. May take 3–5 minutes for the full suite. If the process exits with a signal after "Ran all test suites", the wrapper treats it as success and coverage is written to `coverage/`. Use `test:coverage:nyc` only if you need nyc-specific reporters.
89
+ ---
128
90
 
129
91
  ## Requirements
130
92
 
131
- - **Docker Desktop** - For running containers
132
- - **Node.js 18+** - For running the CLI
133
- - **Azure CLI** - For deploying to Azure (optional)
93
+ - **Docker Desktop** For running containers
94
+ - **Node.js 18+** For running the CLI
95
+ - **Azure CLI** For deploying to Azure (optional)
96
+
97
+ ---
134
98
 
135
99
  ## License
136
100
 
@@ -511,7 +511,7 @@ async function checkAppDirectory(appPath) {
511
511
  * @throws {Error} If required files are missing
512
512
  */
513
513
  async function validateRequiredFiles(appPath, entries) {
514
- const requiredFiles = ['variables.yaml', 'env.template', 'README.md', 'deploy.sh', 'deploy.ps1'];
514
+ const requiredFiles = ['variables.yaml', 'env.template', 'README.md', 'deploy.js'];
515
515
  const missingFiles = [];
516
516
  for (const fileName of requiredFiles) {
517
517
  const filePath = path.join(appPath, fileName);
@@ -311,7 +311,7 @@ async function testMcpConnection(dataplaneUrl, authConfig, serverUrl, token) {
311
311
  }
312
312
 
313
313
  /**
314
- * Get deployment documentation for a system
314
+ * Get deployment documentation for a system (from dataplane DB only)
315
315
  * GET /api/v1/wizard/deployment-docs/{systemKey}
316
316
  * @async
317
317
  * @function getDeploymentDocs
@@ -326,6 +326,28 @@ async function getDeploymentDocs(dataplaneUrl, authConfig, systemKey) {
326
326
  return await client.get(`/api/v1/wizard/deployment-docs/${systemKey}`);
327
327
  }
328
328
 
329
+ /**
330
+ * Generate deployment documentation with variables.yaml and deploy JSON for better quality
331
+ * POST /api/v1/wizard/deployment-docs/{systemKey}
332
+ * Sends deployJson and variablesYaml in the request body so the dataplane can align README with the integration folder.
333
+ * @async
334
+ * @function postDeploymentDocs
335
+ * @param {string} dataplaneUrl - Dataplane base URL
336
+ * @param {Object} authConfig - Authentication configuration
337
+ * @param {string} systemKey - System key identifier
338
+ * @param {Object} [body] - Optional request body (WizardDeploymentDocsRequest)
339
+ * @param {Object} [body.deployJson] - Deploy JSON object (e.g. *-deploy.json content)
340
+ * @param {string} [body.variablesYaml] - variables.yaml file content as string
341
+ * @returns {Promise<Object>} Deployment documentation response (content, contentType, systemKey)
342
+ * @throws {Error} If request fails
343
+ */
344
+ async function postDeploymentDocs(dataplaneUrl, authConfig, systemKey, body = null) {
345
+ const client = new ApiClient(dataplaneUrl, authConfig);
346
+ return await client.post(`/api/v1/wizard/deployment-docs/${systemKey}`, {
347
+ body: body || {}
348
+ });
349
+ }
350
+
329
351
  /**
330
352
  * Get known wizard platforms from dataplane.
331
353
  * GET /api/v1/wizard/platforms
@@ -365,5 +387,6 @@ module.exports = {
365
387
  getPreview,
366
388
  testMcpConnection,
367
389
  getDeploymentDocs,
390
+ postDeploymentDocs,
368
391
  getWizardPlatforms
369
392
  };
package/lib/app/deploy.js CHANGED
@@ -15,7 +15,7 @@ const yaml = require('js-yaml');
15
15
  const chalk = require('chalk');
16
16
  const pushUtils = require('../deployment/push');
17
17
  const logger = require('../utils/logger');
18
- const { detectAppType } = require('../utils/paths');
18
+ const { detectAppType, getBuilderPath, getIntegrationPath } = require('../utils/paths');
19
19
  const { checkApplicationExists } = require('../utils/app-existence');
20
20
  const { loadDeploymentConfig } = require('./deploy-config');
21
21
 
@@ -219,15 +219,16 @@ function displayDeploymentResults(result) {
219
219
  }
220
220
 
221
221
  /**
222
- * Check if app is external and handle external deployment
222
+ * Check if app is external and handle external deployment.
223
+ * When options.type === 'external', forces deployment from integration/<app> (no app register needed).
223
224
  * @async
224
225
  * @function handleExternalDeployment
225
226
  * @param {string} appName - Application name
226
- * @param {Object} options - Deployment options
227
+ * @param {Object} options - Deployment options (type: 'external' to force integration/<app>)
227
228
  * @returns {Promise<Object|null>} Deployment result if external, null otherwise
228
229
  */
229
230
  async function handleExternalDeployment(appName, options) {
230
- const { isExternal } = await detectAppType(appName);
231
+ const { isExternal } = await detectAppType(appName, options);
231
232
  if (isExternal) {
232
233
  const externalDeploy = require('../external-system/deploy');
233
234
  await externalDeploy.deployExternalSystem(appName, options);
@@ -317,6 +318,37 @@ async function executeStandardDeployment(appName, options) {
317
318
  }
318
319
  }
319
320
 
321
+ /**
322
+ * Tries external deploy when builder/<app> does not exist but integration/<app> does.
323
+ * @async
324
+ * @param {string} appName - Application name
325
+ * @param {Object} options - Deployment options
326
+ * @returns {Promise<{usedExternalDeploy: boolean, result: Object|null}>}
327
+ */
328
+ async function tryExternalDeployFallback(appName, options) {
329
+ const builderPath = getBuilderPath(appName);
330
+ const integrationPath = getIntegrationPath(appName);
331
+ let builderExists = false;
332
+ let integrationExists = false;
333
+ try {
334
+ await fs.access(builderPath);
335
+ builderExists = true;
336
+ } catch (e) {
337
+ if (e.code !== 'ENOENT') throw e;
338
+ }
339
+ try {
340
+ await fs.access(integrationPath);
341
+ integrationExists = true;
342
+ } catch (e) {
343
+ if (e.code !== 'ENOENT') throw e;
344
+ }
345
+ if (!builderExists && integrationExists) {
346
+ const fallbackResult = await handleExternalDeployment(appName, { ...options, type: 'external' });
347
+ if (fallbackResult) return { usedExternalDeploy: true, result: fallbackResult };
348
+ }
349
+ return { usedExternalDeploy: false, result: null };
350
+ }
351
+
320
352
  /**
321
353
  * Deploys application to Miso Controller
322
354
  * Orchestrates manifest generation, key creation, and deployment
@@ -338,7 +370,7 @@ async function executeStandardDeployment(appName, options) {
338
370
  */
339
371
  async function deployApp(appName, options = {}) {
340
372
  let controllerUrl = null;
341
- let usedExternalDeploy = false;
373
+ let usedExternalDeploy = options.type === 'external';
342
374
 
343
375
  try {
344
376
  if (!appName || typeof appName !== 'string' || appName.trim().length === 0) {
@@ -347,8 +379,12 @@ async function deployApp(appName, options = {}) {
347
379
  validateAppName(appName);
348
380
 
349
381
  const externalResult = await handleExternalDeployment(appName, options);
350
- if (externalResult) {
351
- return externalResult;
382
+ if (externalResult) return externalResult;
383
+
384
+ const fallback = await tryExternalDeployFallback(appName, options);
385
+ if (fallback.result) {
386
+ usedExternalDeploy = fallback.usedExternalDeploy;
387
+ return fallback.result;
352
388
  }
353
389
  usedExternalDeploy = false;
354
390
 
@@ -50,7 +50,7 @@ function displayWebappSuccess(appName, config, envConversionMessage) {
50
50
 
51
51
  logger.log(chalk.green('\nNext steps:'));
52
52
  logger.log(chalk.white('1. Copy env.template to .env and fill in your values'));
53
- logger.log(chalk.white('2. Run: aifabrix up'));
53
+ logger.log(chalk.white('2. Run: aifabrix up-infra'));
54
54
  logger.log(chalk.white('3. Run: aifabrix build ' + appName));
55
55
  logger.log(chalk.white('4. Run: aifabrix run ' + appName));
56
56
  }
package/lib/app/list.js CHANGED
@@ -164,9 +164,11 @@ function displayApplications(applications, environment, controllerUrl) {
164
164
 
165
165
  logger.log(chalk.bold(`\n📱 ${header}:\n`));
166
166
  applications.forEach((app) => {
167
+ const isExternal = app.configuration?.type === 'external';
168
+ const externalIcon = isExternal ? '🔗 ' : '';
167
169
  const hasPipeline = app.configuration?.pipeline?.isActive ? '✓' : '✗';
168
170
  const urlAndPort = formatUrlAndPort(app);
169
- logger.log(`${hasPipeline} ${chalk.cyan(app.key)} - ${app.displayName} (${app.status || 'unknown'})${urlAndPort}`);
171
+ logger.log(`${externalIcon}${hasPipeline} ${chalk.cyan(app.key)} - ${app.displayName} (${app.status || 'unknown'})${urlAndPort}`);
170
172
  });
171
173
  logger.log(chalk.gray(' To show details for an app: aifabrix app show <appKey>\n'));
172
174
  }
@@ -177,7 +177,7 @@ async function checkPrerequisites(appName, appConfig, debug = false, skipInfraCh
177
177
  .map(([service, _]) => service);
178
178
 
179
179
  if (unhealthyServices.length > 0) {
180
- throw new Error(`Infrastructure services not healthy: ${unhealthyServices.join(', ')}\nRun 'aifabrix up' first`);
180
+ throw new Error(`Infrastructure services not healthy: ${unhealthyServices.join(', ')}\nRun 'aifabrix up-infra' first`);
181
181
  }
182
182
  logger.log(chalk.green('✓ Infrastructure is running'));
183
183
  }
@@ -200,7 +200,7 @@ async function postBuildTasks(appName, buildConfig) {
200
200
  }
201
201
 
202
202
  /**
203
- * Check if app is external type and handle accordingly
203
+ * External apps have no Docker image; deploy JSON is generated by aifabrix json.
204
204
  * @async
205
205
  * @param {string} appName - Application name
206
206
  * @returns {Promise<boolean>} True if external (handled), false if should continue
@@ -208,9 +208,8 @@ async function postBuildTasks(appName, buildConfig) {
208
208
  async function checkExternalAppType(appName) {
209
209
  const variables = await loadVariablesYaml(appName);
210
210
  if (variables.app && variables.app.type === 'external') {
211
- const generator = require('../generator');
212
- const jsonPath = await generator.generateDeployJson(appName);
213
- logger.log(chalk.green(`✓ Generated deployment JSON: ${jsonPath}`));
211
+ logger.log(chalk.blue(`External system: ${appName}`));
212
+ logger.log(chalk.gray('To regenerate deployment JSON, run: aifabrix json ' + appName));
214
213
  return true;
215
214
  }
216
215
  return false;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * AI Fabrix Builder CLI Command Definitions
3
+ *
4
+ * This module wires all CLI command setup and re-exports setupCommands,
5
+ * validateCommand, and handleCommandError for backward compatibility.
6
+ *
7
+ * @fileoverview CLI entry for AI Fabrix Builder; command setup orchestration
8
+ * @author AI Fabrix Team
9
+ * @version 2.0.0
10
+ */
11
+
12
+ const { validateCommand, handleCommandError } = require('../utils/cli-utils');
13
+ const { setupAuthCommands } = require('./setup-auth');
14
+ const { setupInfraCommands } = require('./setup-infra');
15
+ const { setupAppCommands } = require('./setup-app');
16
+ const { setupEnvironmentCommands } = require('./setup-environment');
17
+ const { setupUtilityCommands } = require('./setup-utility');
18
+ const { setupDevCommands } = require('./setup-dev');
19
+ const { setupSecretsCommands } = require('./setup-secrets');
20
+ const { setupExternalSystemCommands } = require('./setup-external-system');
21
+ const { setupAppCommands: setupAppManagementCommands } = require('../commands/app');
22
+ const { setupDatasourceCommands } = require('../commands/datasource');
23
+
24
+ /**
25
+ * Sets up all CLI commands on the Commander program instance
26
+ * @param {Command} program - Commander program instance
27
+ */
28
+ function setupCommands(program) {
29
+ setupInfraCommands(program);
30
+ setupAuthCommands(program);
31
+ setupAppCommands(program);
32
+ setupEnvironmentCommands(program);
33
+ setupAppManagementCommands(program);
34
+ setupDatasourceCommands(program);
35
+ setupUtilityCommands(program);
36
+ setupExternalSystemCommands(program);
37
+ setupDevCommands(program);
38
+ setupSecretsCommands(program);
39
+ }
40
+
41
+ module.exports = {
42
+ setupCommands,
43
+ validateCommand,
44
+ handleCommandError
45
+ };