@aifabrix/builder 2.44.5 → 2.44.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/cli-layout.mdc +1 -1
- package/.cursor/rules/project-rules.mdc +1 -1
- package/.npmrc.token +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +48 -2
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +1 -1
- package/lib/app/restart-display.js +95 -0
- package/lib/app/rotate-secret.js +1 -1
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +44 -12
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +99 -73
- package/lib/build/index.js +75 -45
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +445 -0
- package/lib/cli/setup-app.js +20 -2
- package/lib/cli/setup-auth.js +26 -0
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra.js +134 -61
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility.js +78 -33
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +214 -31
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -338
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +455 -0
- package/lib/commands/setup-prompts.js +388 -0
- package/lib/commands/setup.js +149 -0
- package/lib/commands/teardown.js +228 -0
- package/lib/commands/up-common.js +79 -19
- package/lib/commands/up-dataplane.js +33 -11
- package/lib/commands/up-miso.js +7 -11
- package/lib/commands/upload.js +109 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +6 -5
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +4 -3
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/commands/wizard.js +2 -1
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +432 -0
- package/lib/core/secrets-env-write.js +27 -1
- package/lib/core/secrets-load.js +248 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +4 -1
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -11
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/external-readme.js +71 -2
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +19 -4
- package/lib/utils/health-check.js +135 -105
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +108 -25
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +42 -3
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +24 -10
- package/lib/utils/secrets-utils.js +2 -2
- package/lib/utils/system-builder-root.js +34 -0
- package/lib/utils/url-declarative-resolve-build.js +6 -1
- package/lib/utils/url-declarative-runtime-base-path.js +32 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry.js +23 -12
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +7 -0
- package/templates/applications/miso-controller/env.template +1 -1
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +83 -123
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
package/lib/cli/setup-infra.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
formatProgress,
|
|
3
|
+
formatSuccessLine,
|
|
4
|
+
sectionTitle,
|
|
5
|
+
headerKeyValue
|
|
6
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
2
7
|
/**
|
|
3
8
|
* CLI infrastructure command setup (up-infra, up-platform, up-miso, up-dataplane, down-infra, doctor, status, restart).
|
|
4
9
|
*
|
|
@@ -10,7 +15,6 @@ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
|
10
15
|
const chalk = require('chalk');
|
|
11
16
|
const infra = require('../infrastructure');
|
|
12
17
|
const appLib = require('../app');
|
|
13
|
-
const validator = require('../validation/validator');
|
|
14
18
|
const config = require('../core/config');
|
|
15
19
|
const logger = require('../utils/logger');
|
|
16
20
|
const { handleCommandError, isAuthenticationError } = require('../utils/cli-utils');
|
|
@@ -18,19 +22,29 @@ const { resolveControllerUrl } = require('../utils/controller-url');
|
|
|
18
22
|
const { handleLogin } = require('../commands/login');
|
|
19
23
|
const { handleUpMiso } = require('../commands/up-miso');
|
|
20
24
|
const { handleUpDataplane } = require('../commands/up-dataplane');
|
|
21
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
applyUpPlatformForceConfig,
|
|
27
|
+
cleanBuilderAppDirs,
|
|
28
|
+
prepareUrlsLocalRegistryForUpPlatform
|
|
29
|
+
} = require('../commands/up-common');
|
|
30
|
+
const { runGuidedUpInfra, runGuidedUpMiso, runGuidedUpDataplane, runGuidedUpPlatform, runGuidedDownInfra } = require('./infra-guided');
|
|
22
31
|
const {
|
|
23
32
|
loadInfraStatusSummary,
|
|
24
33
|
formatInfraStatusTitleLine,
|
|
25
34
|
logInfraStatusConfigurationSummary,
|
|
26
35
|
logPaddedFieldRow
|
|
27
36
|
} = require('../utils/infra-status-display');
|
|
37
|
+
const { runDoctorCheck } = require('./doctor-check');
|
|
38
|
+
const {
|
|
39
|
+
getRestartableInfraServiceNames,
|
|
40
|
+
buildRestartInfraHelpLines
|
|
41
|
+
} = require('../constants/infra-compose-service-names');
|
|
28
42
|
|
|
29
43
|
const UP_INFRA_HELP_AFTER = `
|
|
30
44
|
Typical sequence:
|
|
31
45
|
$ aifabrix up-infra
|
|
32
46
|
$ aifabrix up-platform
|
|
33
|
-
Or: aifabrix up-miso, then aifabrix up-dataplane (login required for dataplane)
|
|
47
|
+
Or: aifabrix up-infra, aifabrix up-miso, then aifabrix up-dataplane (login required for dataplane)
|
|
34
48
|
|
|
35
49
|
Full bootstrap example (Traefik, TLS flag, pgAdmin, catalog overrides — matches shipped defaults in infra.parameter.yaml):
|
|
36
50
|
$ aifabrix up-infra --traefik --tls --adminPassword admin123 --adminEmail admin@aifabrix.dev --userPassword user123 --pgAdmin
|
|
@@ -59,16 +73,14 @@ async function persistTlsEnabledFlag(cfg, value) {
|
|
|
59
73
|
await config.saveConfig(cfg);
|
|
60
74
|
const tlsStr = value ? 'true' : 'false';
|
|
61
75
|
const httpStr = value ? 'false' : 'true';
|
|
62
|
-
logger.log(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
);
|
|
76
|
+
logger.log(formatSuccessLine(
|
|
77
|
+
`TLS mode ${value ? 'enabled' : 'disabled'} and saved to config (` +
|
|
78
|
+
'${TLS_ENABLED}=' +
|
|
79
|
+
tlsStr +
|
|
80
|
+
', ${HTTP_ENABLED}=' +
|
|
81
|
+
httpStr +
|
|
82
|
+
' when generating deployment JSON)'
|
|
83
|
+
));
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
/**
|
|
@@ -152,11 +164,27 @@ async function runUpInfraCommand(options) {
|
|
|
152
164
|
});
|
|
153
165
|
}
|
|
154
166
|
|
|
167
|
+
async function maybeHandleUpPlatformAuthRetry(error, options) {
|
|
168
|
+
if (!isAuthenticationError(error)) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const controllerUrl = error.controllerUrl || await resolveControllerUrl();
|
|
172
|
+
if (!options.verbose) {
|
|
173
|
+
logger.log(formatProgress('Authenticating...'));
|
|
174
|
+
} else {
|
|
175
|
+
logger.log(chalk.blue('\nAuthentication required. Running aifabrix login...\n'));
|
|
176
|
+
}
|
|
177
|
+
await handleLogin({ method: 'device', controller: controllerUrl, compact: !options.verbose });
|
|
178
|
+
await handleUpDataplane(options);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
155
182
|
function setupUpInfraCommand(program) {
|
|
156
183
|
program.command('up-infra')
|
|
157
184
|
.description('Start Postgres, Redis; optional pgAdmin, Redis Commander, Traefik')
|
|
158
185
|
.addHelpText('after', UP_INFRA_HELP_AFTER)
|
|
159
186
|
.option('-d, --developer <id>', 'Set developer ID and start infrastructure')
|
|
187
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
160
188
|
.option('--adminPassword <password>', 'Override {{adminPassword}} defaults (Postgres, pgAdmin, Redis Commander, catalog literals)')
|
|
161
189
|
.option('--adminEmail <email>', 'Override {{adminEmail}} default (e.g. pgAdmin login email)')
|
|
162
190
|
.option('--userPassword <password>', 'Override {{userPassword}} default (e.g. Keycloak default user password)')
|
|
@@ -170,6 +198,11 @@ function setupUpInfraCommand(program) {
|
|
|
170
198
|
.option('--no-tls', 'Disable TLS mode (${TLS_ENABLED}=false, ${HTTP_ENABLED}=true)')
|
|
171
199
|
.action(async(options) => {
|
|
172
200
|
try {
|
|
201
|
+
if (!options.verbose) {
|
|
202
|
+
await runGuidedUpInfra(options, runUpInfraCommand);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
173
206
|
await runUpInfraCommand(options);
|
|
174
207
|
} catch (error) {
|
|
175
208
|
handleCommandError(error, 'up-infra');
|
|
@@ -184,30 +217,47 @@ function setupUpPlatformCommand(program) {
|
|
|
184
217
|
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
185
218
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
186
219
|
.option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1, dataplane=myreg/d:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
|
|
220
|
+
.option('--base', 'Resolve platform images from manifest only (default: true)', true)
|
|
221
|
+
.option('--verbose', 'Show full orchestration output (default is guided installer)')
|
|
187
222
|
.option(
|
|
188
223
|
'-f, --force',
|
|
189
224
|
'Reset CLI auth (clear all device/client tokens, set environment to dev, set default controller URL from developer-id), clean builder/keycloak, builder/miso-controller, builder/dataplane, then re-fetch from templates'
|
|
190
225
|
)
|
|
191
226
|
.action(async(options) => {
|
|
192
227
|
try {
|
|
228
|
+
let platformForceCleanSummary = null;
|
|
193
229
|
if (options.force) {
|
|
194
|
-
await applyUpPlatformForceConfig();
|
|
195
|
-
await cleanBuilderAppDirs(['keycloak', 'miso-controller', 'dataplane']
|
|
230
|
+
const forceSummary = await applyUpPlatformForceConfig({ silent: !options.verbose });
|
|
231
|
+
const cleanedApps = await cleanBuilderAppDirs(['keycloak', 'miso-controller', 'dataplane'], {
|
|
232
|
+
silent: !options.verbose
|
|
233
|
+
});
|
|
234
|
+
if (!options.verbose) {
|
|
235
|
+
platformForceCleanSummary = { forceSummary, cleanedApps };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!options.verbose) {
|
|
240
|
+
await runGuidedUpPlatform(
|
|
241
|
+
options,
|
|
242
|
+
handleUpMiso,
|
|
243
|
+
handleUpDataplane,
|
|
244
|
+
handleLogin,
|
|
245
|
+
platformForceCleanSummary
|
|
246
|
+
);
|
|
247
|
+
return;
|
|
196
248
|
}
|
|
249
|
+
|
|
250
|
+
await prepareUrlsLocalRegistryForUpPlatform();
|
|
197
251
|
await handleUpMiso(options);
|
|
198
252
|
await handleUpDataplane(options);
|
|
199
253
|
} catch (error) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
logger.log(chalk.blue('\nAuthentication required. Running aifabrix login...\n'));
|
|
203
|
-
try {
|
|
204
|
-
await handleLogin({ method: 'device', controller: controllerUrl });
|
|
205
|
-
await handleUpDataplane(options);
|
|
254
|
+
try {
|
|
255
|
+
if (await maybeHandleUpPlatformAuthRetry(error, options)) {
|
|
206
256
|
return;
|
|
207
|
-
} catch (loginOrRetryError) {
|
|
208
|
-
handleCommandError(loginOrRetryError, 'up-platform');
|
|
209
|
-
process.exit(1);
|
|
210
257
|
}
|
|
258
|
+
} catch (loginOrRetryError) {
|
|
259
|
+
handleCommandError(loginOrRetryError, 'up-platform');
|
|
260
|
+
process.exit(1);
|
|
211
261
|
}
|
|
212
262
|
handleCommandError(error, 'up-platform');
|
|
213
263
|
process.exit(1);
|
|
@@ -221,12 +271,19 @@ function setupUpMisoCommand(program) {
|
|
|
221
271
|
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
222
272
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
223
273
|
.option('-i, --image <key>=<value>', 'Override image (e.g. keycloak=myreg/k:v1, miso-controller=myreg/m:v1); can be repeated', (v, prev) => (prev || []).concat([v]))
|
|
274
|
+
.option('--base', 'Resolve platform images from manifest only (default: true)', true)
|
|
224
275
|
.option('-f, --force', 'Clean builder/keycloak and builder/miso-controller and re-fetch from templates')
|
|
276
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
225
277
|
.action(async(options) => {
|
|
226
278
|
try {
|
|
227
279
|
if (options.force) {
|
|
228
280
|
await cleanBuilderAppDirs(['keycloak', 'miso-controller']);
|
|
229
281
|
}
|
|
282
|
+
if (!options.verbose) {
|
|
283
|
+
await runGuidedUpMiso(options, handleUpMiso);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
230
287
|
await handleUpMiso(options);
|
|
231
288
|
} catch (error) {
|
|
232
289
|
handleCommandError(error, 'up-miso');
|
|
@@ -237,23 +294,34 @@ function setupUpMisoCommand(program) {
|
|
|
237
294
|
|
|
238
295
|
function setupUpDataplaneCommand(program) {
|
|
239
296
|
program.command('up-dataplane')
|
|
240
|
-
.description('Register, deploy, run dataplane locally (dev env; login required)')
|
|
297
|
+
.description('Register, deploy, run dataplane locally (dev env; needs up-infra; login required)')
|
|
241
298
|
.option('-r, --registry <url>', 'Override registry for dataplane image')
|
|
242
299
|
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
243
300
|
.option('-i, --image <ref>', 'Override dataplane image reference (e.g. myreg/dataplane:latest)')
|
|
301
|
+
.option('--base', 'Resolve dataplane image from manifest only when running locally (default: true)', true)
|
|
244
302
|
.option('-f, --force', 'Clean builder/dataplane and re-fetch from templates')
|
|
303
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
245
304
|
.action(async(options) => {
|
|
246
305
|
try {
|
|
247
306
|
if (options.force) {
|
|
248
307
|
await cleanBuilderAppDirs(['dataplane']);
|
|
249
308
|
}
|
|
309
|
+
if (!options.verbose) {
|
|
310
|
+
await runGuidedUpDataplane(options, handleUpDataplane);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
250
314
|
await handleUpDataplane(options);
|
|
251
315
|
} catch (error) {
|
|
252
316
|
if (isAuthenticationError(error)) {
|
|
253
317
|
const controllerUrl = error.controllerUrl || await resolveControllerUrl();
|
|
254
|
-
|
|
318
|
+
if (!options.verbose) {
|
|
319
|
+
logger.log(formatProgress('Authenticating...'));
|
|
320
|
+
} else {
|
|
321
|
+
logger.log(chalk.blue('\nAuthentication required. Running aifabrix login...\n'));
|
|
322
|
+
}
|
|
255
323
|
try {
|
|
256
|
-
await handleLogin({ method: 'device', controller: controllerUrl });
|
|
324
|
+
await handleLogin({ method: 'device', controller: controllerUrl, compact: !options.verbose });
|
|
257
325
|
await handleUpDataplane(options);
|
|
258
326
|
return;
|
|
259
327
|
} catch (loginOrRetryError) {
|
|
@@ -271,8 +339,14 @@ function setupDownInfraCommand(program) {
|
|
|
271
339
|
program.command('down-infra [service|app]')
|
|
272
340
|
.description('Stop all infra, or stop one app; use -v to remove volumes')
|
|
273
341
|
.option('-v, --volumes', 'Remove volumes (deletes all data)')
|
|
342
|
+
.option('--verbose', 'Show full orchestration output (default is guided summary)')
|
|
274
343
|
.action(async(appName, options) => {
|
|
275
344
|
try {
|
|
345
|
+
if (!options.verbose) {
|
|
346
|
+
await runGuidedDownInfra(appName, options, infra, appLib);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
276
350
|
if (typeof appName === 'string' && appName.trim().length > 0) {
|
|
277
351
|
await appLib.downApp(appName, { volumes: !!options.volumes });
|
|
278
352
|
} else {
|
|
@@ -291,33 +365,7 @@ function setupDoctorCommand(program) {
|
|
|
291
365
|
.description('Check Docker, ports, secrets, and infra health')
|
|
292
366
|
.action(async() => {
|
|
293
367
|
try {
|
|
294
|
-
|
|
295
|
-
logger.log('\n🔍 AI Fabrix Environment Check\n');
|
|
296
|
-
logger.log(`Docker: ${result.docker === 'ok' ? '✔ Running' : '✖ Not available'}`);
|
|
297
|
-
logger.log(`Ports: ${result.ports === 'ok' ? '✔ Available' : '⚠ Some ports in use'}`);
|
|
298
|
-
logger.log(`Secrets: ${result.secrets === 'ok' ? '✔ Configured' : '✖ Missing'}`);
|
|
299
|
-
if (result.recommendations.length > 0) {
|
|
300
|
-
logger.log('\n📋 Recommendations:');
|
|
301
|
-
result.recommendations.forEach(rec => logger.log(` • ${rec}`));
|
|
302
|
-
}
|
|
303
|
-
if (result.docker === 'ok') {
|
|
304
|
-
try {
|
|
305
|
-
const cfg = await config.getConfig();
|
|
306
|
-
const health = await infra.checkInfraHealth(null, {
|
|
307
|
-
pgadmin: cfg.pgadmin !== false,
|
|
308
|
-
redisCommander: cfg.redisCommander !== false,
|
|
309
|
-
traefik: !!cfg.traefik
|
|
310
|
-
});
|
|
311
|
-
logger.log('\n🏥 Infrastructure Health:');
|
|
312
|
-
Object.entries(health).forEach(([service, status]) => {
|
|
313
|
-
const icon = status === 'healthy' ? '✔' : status === 'unknown' ? '❓' : '✖';
|
|
314
|
-
logger.log(` ${icon} ${service}: ${status}`);
|
|
315
|
-
});
|
|
316
|
-
} catch (error) {
|
|
317
|
-
logger.log('\n🏥 Infrastructure: Not running');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
logger.log('');
|
|
368
|
+
await runDoctorCheck();
|
|
321
369
|
} catch (error) {
|
|
322
370
|
handleCommandError(error, 'doctor');
|
|
323
371
|
process.exit(1);
|
|
@@ -365,19 +413,44 @@ function setupStatusCommand(program) {
|
|
|
365
413
|
});
|
|
366
414
|
}
|
|
367
415
|
|
|
368
|
-
const
|
|
416
|
+
const RESTART_INFRA_SERVICE_NAMES = getRestartableInfraServiceNames();
|
|
417
|
+
|
|
418
|
+
const RESTART_COMMAND_HELP_AFTER = `
|
|
419
|
+
Infra — use these exact Docker Compose service names:
|
|
420
|
+
${buildRestartInfraHelpLines()}
|
|
421
|
+
|
|
422
|
+
Optional services (pgadmin, redis-commander, traefik) only exist if you enabled them when running up-infra.
|
|
423
|
+
|
|
424
|
+
Builder apps (examples):
|
|
425
|
+
keycloak, miso-controller, dataplane
|
|
426
|
+
|
|
427
|
+
Examples:
|
|
428
|
+
$ aifabrix restart postgres
|
|
429
|
+
$ aifabrix restart traefik
|
|
430
|
+
$ aifabrix restart miso-controller
|
|
431
|
+
`;
|
|
369
432
|
|
|
370
433
|
function setupRestartCommand(program) {
|
|
371
434
|
program.command('restart <service|app>')
|
|
372
|
-
.description(
|
|
435
|
+
.description(
|
|
436
|
+
'Restart one infra compose service (postgres, redis, pgadmin, redis-commander, traefik) or a builder app container'
|
|
437
|
+
)
|
|
438
|
+
.addHelpText('after', RESTART_COMMAND_HELP_AFTER)
|
|
373
439
|
.action(async(service) => {
|
|
374
440
|
try {
|
|
375
|
-
if (
|
|
376
|
-
|
|
377
|
-
logger.log(
|
|
441
|
+
if (RESTART_INFRA_SERVICE_NAMES.includes(service)) {
|
|
442
|
+
logger.log('');
|
|
443
|
+
logger.log(sectionTitle('Restart'));
|
|
444
|
+
logger.log(headerKeyValue('Infra service:', service));
|
|
445
|
+
logger.log(formatProgress(`Restarting ${service}…`));
|
|
446
|
+
await infra.restartService(service, { suppressProgressLog: true });
|
|
447
|
+
logger.log(formatSuccessLine(`${service} restarted successfully`));
|
|
378
448
|
} else {
|
|
449
|
+
logger.log('');
|
|
450
|
+
logger.log(sectionTitle('Restart'));
|
|
451
|
+
logger.log(headerKeyValue('Application:', service));
|
|
379
452
|
await appLib.restartApp(service);
|
|
380
|
-
logger.log(
|
|
453
|
+
logger.log(formatSuccessLine(`${service} restarted successfully`));
|
|
381
454
|
}
|
|
382
455
|
} catch (error) {
|
|
383
456
|
handleCommandError(error, 'restart');
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI integration-client command setup (Controller OAuth / API clients).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Integration client CLI definitions
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const {
|
|
11
|
+
runIntegrationClientCreate,
|
|
12
|
+
runIntegrationClientList,
|
|
13
|
+
runIntegrationClientRotateSecret,
|
|
14
|
+
runIntegrationClientDelete,
|
|
15
|
+
runIntegrationClientUpdateGroups,
|
|
16
|
+
runIntegrationClientUpdateRedirectUris
|
|
17
|
+
} = require('../commands/integration-client');
|
|
18
|
+
|
|
19
|
+
const HELP_AFTER = `
|
|
20
|
+
Integration clients are machine identities for integrations, CI, Postman OAuth2, or API access.
|
|
21
|
+
Use: list (integration-client:read), create (integration-client:create), rotate-secret,
|
|
22
|
+
update-groups, update-redirect-uris (integration-client:update), delete (integration-client:delete).
|
|
23
|
+
The controller returns a one-time clientSecret on create and rotate-secret—save it immediately;
|
|
24
|
+
it cannot be retrieved again.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
$ aifabrix integration-client create --key postman --display-name "Postman client" \\
|
|
28
|
+
--redirect-uris https://oauth.pstmn.io/v1/callback --group-names AI-Fabrix-Platform-Admins
|
|
29
|
+
$ aifabrix integration-client list
|
|
30
|
+
$ aifabrix integration-client rotate-secret --id <uuid>
|
|
31
|
+
$ aifabrix integration-client delete --id <uuid>
|
|
32
|
+
$ aifabrix integration-client update-groups --id <uuid> --group-names Group1,Group2
|
|
33
|
+
$ aifabrix integration-client update-redirect-uris --id <uuid> --redirect-uris https://app.example.com/callback
|
|
34
|
+
|
|
35
|
+
Run "aifabrix login" first.`;
|
|
36
|
+
|
|
37
|
+
function parseOptionalInt(val) {
|
|
38
|
+
return (val !== undefined && val !== null) ? parseInt(val, 10) : undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function addCreateCommand(integrationClient) {
|
|
42
|
+
integrationClient.command('create')
|
|
43
|
+
.description('Create an integration client and receive a one-time clientSecret (save it now; it will not be shown again)')
|
|
44
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
45
|
+
.option('-k, --key <key>', 'Stable key (lowercase alphanumeric and hyphens; required)')
|
|
46
|
+
.option('-n, --display-name <name>', 'Display name (required)')
|
|
47
|
+
.option('--keycloak-client-id <id>', 'Optional fixed Keycloak client id (when omitted, the server assigns one)')
|
|
48
|
+
.option('--redirect-uris <uris>', 'Comma-separated OAuth2 redirect URIs (required)')
|
|
49
|
+
.option('--group-names <names>', 'Comma-separated group names (optional; omit for OAuth-only clients)')
|
|
50
|
+
.option('-d, --description <description>', 'Optional description')
|
|
51
|
+
.action(async(options) => {
|
|
52
|
+
try {
|
|
53
|
+
await runIntegrationClientCreate({
|
|
54
|
+
controller: options.controller,
|
|
55
|
+
key: options.key,
|
|
56
|
+
displayName: options.displayName,
|
|
57
|
+
keycloakClientId: options.keycloakClientId,
|
|
58
|
+
redirectUris: options.redirectUris,
|
|
59
|
+
groupNames: options.groupNames,
|
|
60
|
+
description: options.description
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
handleCommandError(error, 'integration-client create');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function addListCommand(integrationClient) {
|
|
70
|
+
integrationClient.command('list')
|
|
71
|
+
.description('List integration clients (supports pagination and search)')
|
|
72
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
73
|
+
.option('--page <n>', 'Page number')
|
|
74
|
+
.option('--page-size <n>', 'Items per page')
|
|
75
|
+
.option('--search <term>', 'Search term')
|
|
76
|
+
.option('--sort <field>', 'Sort field/direction')
|
|
77
|
+
.option('--filter <expr>', 'Filter expression')
|
|
78
|
+
.action(async(options) => {
|
|
79
|
+
try {
|
|
80
|
+
await runIntegrationClientList({
|
|
81
|
+
controller: options.controller,
|
|
82
|
+
page: parseOptionalInt(options.page),
|
|
83
|
+
pageSize: parseOptionalInt(options.pageSize),
|
|
84
|
+
search: options.search,
|
|
85
|
+
sort: options.sort,
|
|
86
|
+
filter: options.filter
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
handleCommandError(error, 'integration-client list');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function addRotateSecretCommand(integrationClient) {
|
|
96
|
+
integrationClient.command('rotate-secret')
|
|
97
|
+
.description('Rotate (regenerate) secret for an integration client; new secret shown once only')
|
|
98
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
99
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
100
|
+
.action(async(options) => {
|
|
101
|
+
try {
|
|
102
|
+
await runIntegrationClientRotateSecret({ controller: options.controller, id: options.id });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
handleCommandError(error, 'integration-client rotate-secret');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function addDeleteCommand(integrationClient) {
|
|
111
|
+
integrationClient.command('delete')
|
|
112
|
+
.description('Delete (deactivate) an integration client')
|
|
113
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
114
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
115
|
+
.action(async(options) => {
|
|
116
|
+
try {
|
|
117
|
+
await runIntegrationClientDelete({ controller: options.controller, id: options.id });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
handleCommandError(error, 'integration-client delete');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function addUpdateGroupsCommand(integrationClient) {
|
|
126
|
+
integrationClient.command('update-groups')
|
|
127
|
+
.description('Update group assignments for an integration client')
|
|
128
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
129
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
130
|
+
.option('--group-names <names>', 'Comma-separated group names (required)')
|
|
131
|
+
.action(async(options) => {
|
|
132
|
+
try {
|
|
133
|
+
await runIntegrationClientUpdateGroups({
|
|
134
|
+
controller: options.controller,
|
|
135
|
+
id: options.id,
|
|
136
|
+
groupNames: options.groupNames
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
handleCommandError(error, 'integration-client update-groups');
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function addUpdateRedirectUrisCommand(integrationClient) {
|
|
146
|
+
integrationClient.command('update-redirect-uris')
|
|
147
|
+
.description('Update redirect URIs for an integration client (min 1)')
|
|
148
|
+
.option('--controller <url>', 'Controller base URL (default: from config)')
|
|
149
|
+
.option('--id <uuid>', 'Integration client ID (required)')
|
|
150
|
+
.option('--redirect-uris <uris>', 'Comma-separated redirect URIs (required, min 1)')
|
|
151
|
+
.action(async(options) => {
|
|
152
|
+
try {
|
|
153
|
+
await runIntegrationClientUpdateRedirectUris({
|
|
154
|
+
controller: options.controller,
|
|
155
|
+
id: options.id,
|
|
156
|
+
redirectUris: options.redirectUris
|
|
157
|
+
});
|
|
158
|
+
} catch (error) {
|
|
159
|
+
handleCommandError(error, 'integration-client update-redirect-uris');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Registers integration-client commands
|
|
167
|
+
* @param {Command} program - Commander program instance
|
|
168
|
+
*/
|
|
169
|
+
function setupIntegrationClientCommands(program) {
|
|
170
|
+
const integrationClient = program
|
|
171
|
+
.command('integration-client')
|
|
172
|
+
.description('OAuth integration clients on Controller (integrations, CI, API access)')
|
|
173
|
+
.addHelpText('after', HELP_AFTER);
|
|
174
|
+
addCreateCommand(integrationClient);
|
|
175
|
+
addListCommand(integrationClient);
|
|
176
|
+
addRotateSecretCommand(integrationClient);
|
|
177
|
+
addDeleteCommand(integrationClient);
|
|
178
|
+
addUpdateGroupsCommand(integrationClient);
|
|
179
|
+
addUpdateRedirectUrisCommand(integrationClient);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = { setupIntegrationClientCommands };
|
|
@@ -17,11 +17,30 @@ function setupParametersCommands(program) {
|
|
|
17
17
|
|
|
18
18
|
parameters
|
|
19
19
|
.command('validate')
|
|
20
|
-
.description(
|
|
20
|
+
.description(
|
|
21
|
+
'Validate builder/*/env.template kv:// references against infra.parameter.yaml'
|
|
22
|
+
)
|
|
21
23
|
.option('--catalog <path>', 'Override path to infra.parameter.yaml')
|
|
24
|
+
.option('--verbose', 'Print scanned files and scan summary')
|
|
25
|
+
.addHelpText(
|
|
26
|
+
'after',
|
|
27
|
+
`
|
|
28
|
+
Examples:
|
|
29
|
+
aifabrix parameters validate
|
|
30
|
+
aifabrix parameters validate --verbose
|
|
31
|
+
aifabrix parameters validate --catalog ./lib/schema/infra.parameter.yaml
|
|
32
|
+
|
|
33
|
+
Notes:
|
|
34
|
+
- Scans builder/* apps only (integration/* is intentionally skipped).
|
|
35
|
+
- Extracts kv://KEY references from env.template and checks KEY coverage in the catalog.
|
|
36
|
+
`
|
|
37
|
+
)
|
|
22
38
|
.action(async(opts) => {
|
|
23
39
|
try {
|
|
24
|
-
const result = await handleParametersValidate({
|
|
40
|
+
const result = await handleParametersValidate({
|
|
41
|
+
catalogPath: opts.catalog,
|
|
42
|
+
verbose: Boolean(opts.verbose)
|
|
43
|
+
});
|
|
25
44
|
if (!result.valid) process.exit(1);
|
|
26
45
|
} catch (error) {
|
|
27
46
|
handleCommandError(error, 'parameters validate');
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI registration for `aifabrix setup` and `aifabrix teardown`.
|
|
3
|
+
*
|
|
4
|
+
* `setup` is the one-shot platform installer. When no infrastructure is
|
|
5
|
+
* detected it runs a small wizard (admin email/password, AI tool keys) and
|
|
6
|
+
* then `up-infra` + `up-platform`. When infra is already up, it offers a
|
|
7
|
+
* mode menu (re-install, wipe data, clean install files, update images).
|
|
8
|
+
*
|
|
9
|
+
* `teardown` is the symmetrical inverse of `setup`: `down-infra -v` plus a
|
|
10
|
+
* full clean of the AI Fabrix system directory (everything except
|
|
11
|
+
* `config.yaml`).
|
|
12
|
+
*
|
|
13
|
+
* @fileoverview CLI command setup for setup/teardown
|
|
14
|
+
* @author AI Fabrix Team
|
|
15
|
+
* @version 2.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
21
|
+
const { handleSetup } = require('../commands/setup');
|
|
22
|
+
const { handleTeardown } = require('../commands/teardown');
|
|
23
|
+
|
|
24
|
+
const SETUP_HELP_AFTER = `
|
|
25
|
+
What this command does:
|
|
26
|
+
- With no infra running: prompts for admin email/password (used for Postgres, pgAdmin, Keycloak), prompts for an AI tool (OpenAI or Azure OpenAI) only when keys are not already set, then runs up-infra and up-platform.
|
|
27
|
+
- With infra running: shows a mode menu:
|
|
28
|
+
1) Re-install — stop infra and remove all volumes, then up-infra + up-platform --force.
|
|
29
|
+
2) Wipe data — drop every database and DB user, then up-infra + up-platform --force.
|
|
30
|
+
3) Clean installation files — remove user-local secrets, then up-infra + up-platform --force.
|
|
31
|
+
4) Update images — pull the latest infra and platform images, then up-infra + up-platform.
|
|
32
|
+
|
|
33
|
+
AI tool keys are read from the user-local file (~/.aifabrix/secrets.local.yaml) merged with the shared aifabrix-secrets file. If either source already provides keys, the AI tool prompt is skipped.
|
|
34
|
+
|
|
35
|
+
Use 'aifabrix teardown' to fully remove the local installation.
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const TEARDOWN_HELP_AFTER = `
|
|
39
|
+
What this command does:
|
|
40
|
+
- Runs down-infra -v (stops all infra + apps, removes every Docker volume).
|
|
41
|
+
- Removes every file and subfolder inside ~/.aifabrix/ EXCEPT config.yaml.
|
|
42
|
+
This includes secrets.local.yaml, admin-secrets.env, auth/token files,
|
|
43
|
+
and infra-dev*/ directories.
|
|
44
|
+
|
|
45
|
+
This is the symmetrical inverse of 'aifabrix setup'. Use --yes / -y to skip the confirmation prompt in CI.
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Register the setup command on the Commander program.
|
|
50
|
+
* @param {import('commander').Command} program
|
|
51
|
+
*/
|
|
52
|
+
function registerSetup(program) {
|
|
53
|
+
program
|
|
54
|
+
.command('setup')
|
|
55
|
+
.description('Install or refresh the full AI Fabrix platform (infra + miso + dataplane)')
|
|
56
|
+
.option('-d, --developer <id>', 'Pin developer ID before fresh install (fresh path only; ignored when infra is already up)')
|
|
57
|
+
.option('-y, --yes', 'Skip destructive confirmation prompts (re-install, wipe data, teardown)')
|
|
58
|
+
.addHelpText('after', SETUP_HELP_AFTER)
|
|
59
|
+
.action(async(options) => {
|
|
60
|
+
try {
|
|
61
|
+
await handleSetup(options || {});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
handleCommandError(error, 'setup');
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Register the teardown command on the Commander program.
|
|
71
|
+
* @param {import('commander').Command} program
|
|
72
|
+
*/
|
|
73
|
+
function registerTeardown(program) {
|
|
74
|
+
program
|
|
75
|
+
.command('teardown')
|
|
76
|
+
.description('Tear down local AI Fabrix infra and clean ~/.aifabrix/ except config.yaml')
|
|
77
|
+
.option('-y, --yes', 'Skip the confirmation prompt')
|
|
78
|
+
.addHelpText('after', TEARDOWN_HELP_AFTER)
|
|
79
|
+
.action(async(options) => {
|
|
80
|
+
try {
|
|
81
|
+
await handleTeardown(options || {});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
handleCommandError(error, 'teardown');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Register all setup-platform commands on the Commander program.
|
|
91
|
+
* @param {import('commander').Command} program
|
|
92
|
+
*/
|
|
93
|
+
function setupPlatformCommands(program) {
|
|
94
|
+
registerSetup(program);
|
|
95
|
+
registerTeardown(program);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
setupPlatformCommands,
|
|
100
|
+
registerSetup,
|
|
101
|
+
registerTeardown
|
|
102
|
+
};
|