@aifabrix/builder 2.36.2 ā 2.37.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.
- package/README.md +68 -104
- package/lib/app/display.js +1 -1
- package/lib/app/run-helpers.js +1 -1
- package/lib/cli/index.js +45 -0
- package/lib/cli/setup-app.js +229 -0
- package/lib/cli/setup-auth.js +88 -0
- package/lib/cli/setup-dev.js +101 -0
- package/lib/cli/setup-environment.js +53 -0
- package/lib/cli/setup-external-system.js +86 -0
- package/lib/cli/setup-infra.js +219 -0
- package/lib/cli/setup-secrets.js +48 -0
- package/lib/cli/setup-utility.js +202 -0
- package/lib/cli.js +7 -961
- package/lib/commands/up-miso.js +1 -1
- package/lib/core/config.js +10 -0
- package/lib/core/ensure-encryption-key.js +56 -0
- package/lib/generator/wizard.js +19 -34
- package/lib/infrastructure/helpers.js +1 -1
- package/lib/utils/help-builder.js +5 -2
- package/package.json +1 -1
- package/templates/applications/README.md.hbs +3 -3
- package/templates/applications/dataplane/variables.yaml +0 -2
- package/templates/applications/miso-controller/variables.yaml +0 -2
- package/templates/external-system/deploy.js.hbs +58 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI developer configuration command setup (dev config, dev set-id).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Developer command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const config = require('../core/config');
|
|
11
|
+
const devConfig = require('../utils/dev-config');
|
|
12
|
+
const logger = require('../utils/logger');
|
|
13
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Display developer configuration
|
|
17
|
+
* @param {string} devId - Developer ID
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
async function displayDevConfig(devId) {
|
|
21
|
+
const devIdNum = parseInt(devId, 10);
|
|
22
|
+
const ports = devConfig.getDevPorts(devIdNum);
|
|
23
|
+
const configVars = [
|
|
24
|
+
{ key: 'aifabrix-home', value: await config.getAifabrixHomeOverride() },
|
|
25
|
+
{ key: 'aifabrix-secrets', value: await config.getAifabrixSecretsPath() },
|
|
26
|
+
{ key: 'aifabrix-env-config', value: await config.getAifabrixEnvConfigPath() }
|
|
27
|
+
].filter(v => v.value);
|
|
28
|
+
|
|
29
|
+
logger.log('\nš§ Developer Configuration\n');
|
|
30
|
+
logger.log(`Developer ID: ${devId}`);
|
|
31
|
+
logger.log('\nPorts:');
|
|
32
|
+
logger.log(` App: ${ports.app}`);
|
|
33
|
+
logger.log(` Postgres: ${ports.postgres}`);
|
|
34
|
+
logger.log(` Redis: ${ports.redis}`);
|
|
35
|
+
logger.log(` pgAdmin: ${ports.pgadmin}`);
|
|
36
|
+
logger.log(` Redis Commander: ${ports.redisCommander}`);
|
|
37
|
+
|
|
38
|
+
if (configVars.length > 0) {
|
|
39
|
+
logger.log('\nConfiguration:');
|
|
40
|
+
configVars.forEach(v => logger.log(` ${v.key}: ${v.value}`));
|
|
41
|
+
}
|
|
42
|
+
logger.log('');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Sets up developer configuration commands
|
|
47
|
+
* @param {Command} program - Commander program instance
|
|
48
|
+
*/
|
|
49
|
+
function setupDevCommands(program) {
|
|
50
|
+
const dev = program
|
|
51
|
+
.command('dev')
|
|
52
|
+
.description('Developer configuration and isolation');
|
|
53
|
+
|
|
54
|
+
dev
|
|
55
|
+
.command('config')
|
|
56
|
+
.description('Show or set developer configuration')
|
|
57
|
+
.option('--set-id <id>', 'Set developer ID')
|
|
58
|
+
.action(async(options) => {
|
|
59
|
+
try {
|
|
60
|
+
const setIdValue = options.setId || options['set-id'];
|
|
61
|
+
if (setIdValue) {
|
|
62
|
+
const digitsOnly = /^[0-9]+$/.test(setIdValue);
|
|
63
|
+
if (!digitsOnly) {
|
|
64
|
+
throw new Error('Developer ID must be a non-negative digit string (0 = default infra, > 0 = developer-specific)');
|
|
65
|
+
}
|
|
66
|
+
await config.setDeveloperId(setIdValue);
|
|
67
|
+
process.env.AIFABRIX_DEVELOPERID = setIdValue;
|
|
68
|
+
logger.log(chalk.green(`ā Developer ID set to ${setIdValue}`));
|
|
69
|
+
await displayDevConfig(setIdValue);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const devId = await config.getDeveloperId();
|
|
74
|
+
await displayDevConfig(devId);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
handleCommandError(error, 'dev config');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
dev
|
|
82
|
+
.command('set-id <id>')
|
|
83
|
+
.description('Set developer ID (convenience alias for "dev config --set-id")')
|
|
84
|
+
.action(async(id) => {
|
|
85
|
+
try {
|
|
86
|
+
const digitsOnly = /^[0-9]+$/.test(id);
|
|
87
|
+
if (!digitsOnly) {
|
|
88
|
+
throw new Error('Developer ID must be a non-negative digit string (0 = default infra, > 0 = developer-specific)');
|
|
89
|
+
}
|
|
90
|
+
await config.setDeveloperId(id);
|
|
91
|
+
process.env.AIFABRIX_DEVELOPERID = id;
|
|
92
|
+
logger.log(chalk.green(`ā Developer ID set to ${id}`));
|
|
93
|
+
await displayDevConfig(id);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
handleCommandError(error, 'dev set-id');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { setupDevCommands };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI environment deployment command setup (environment deploy, env deploy).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Environment command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets up environment deployment commands
|
|
13
|
+
* @param {Command} program - Commander program instance
|
|
14
|
+
*/
|
|
15
|
+
function setupEnvironmentCommands(program) {
|
|
16
|
+
const deployEnvHandler = async(envKey, options) => {
|
|
17
|
+
try {
|
|
18
|
+
const environmentDeploy = require('../deployment/environment');
|
|
19
|
+
await environmentDeploy.deployEnvironment(envKey, options);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
handleCommandError(error, 'environment deploy');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const environment = program
|
|
27
|
+
.command('environment')
|
|
28
|
+
.description('Manage environments');
|
|
29
|
+
|
|
30
|
+
environment
|
|
31
|
+
.command('deploy <env>')
|
|
32
|
+
.description('Deploy/setup environment in Miso Controller')
|
|
33
|
+
.option('--config <file>', 'Environment configuration file')
|
|
34
|
+
.option('--skip-validation', 'Skip environment validation')
|
|
35
|
+
.option('--poll', 'Poll for deployment status', true)
|
|
36
|
+
.option('--no-poll', 'Do not poll for status')
|
|
37
|
+
.action(deployEnvHandler);
|
|
38
|
+
|
|
39
|
+
const env = program
|
|
40
|
+
.command('env')
|
|
41
|
+
.description('Environment management (alias for environment)');
|
|
42
|
+
|
|
43
|
+
env
|
|
44
|
+
.command('deploy <env>')
|
|
45
|
+
.description('Deploy/setup environment in Miso Controller')
|
|
46
|
+
.option('--config <file>', 'Environment configuration file')
|
|
47
|
+
.option('--skip-validation', 'Skip environment validation')
|
|
48
|
+
.option('--poll', 'Poll for deployment status', true)
|
|
49
|
+
.option('--no-poll', 'Do not poll for status')
|
|
50
|
+
.action(deployEnvHandler);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { setupEnvironmentCommands };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI external system command setup (download, delete, test, test-integration).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview External system command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets up external system commands
|
|
13
|
+
* @param {Command} program - Commander program instance
|
|
14
|
+
*/
|
|
15
|
+
function setupExternalSystemCommands(program) {
|
|
16
|
+
program.command('download <system-key>')
|
|
17
|
+
.description('Download external system from dataplane to local development structure')
|
|
18
|
+
.option('--dry-run', 'Show what would be downloaded without actually downloading')
|
|
19
|
+
.action(async(systemKey, options) => {
|
|
20
|
+
try {
|
|
21
|
+
const download = require('../external-system/download');
|
|
22
|
+
await download.downloadExternalSystem(systemKey, options);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
handleCommandError(error, 'download');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
program.command('delete <system-key>')
|
|
30
|
+
.description('Delete external system from dataplane (also deletes all associated datasources)')
|
|
31
|
+
.option('--type <type>', 'Application type (external) - required for external systems')
|
|
32
|
+
.option('--yes', 'Skip confirmation prompt')
|
|
33
|
+
.option('--force', 'Skip confirmation prompt (alias for --yes)')
|
|
34
|
+
.action(async(systemKey, options) => {
|
|
35
|
+
try {
|
|
36
|
+
if (options.type !== 'external') {
|
|
37
|
+
throw new Error('Delete command for external systems requires --type external');
|
|
38
|
+
}
|
|
39
|
+
const externalDelete = require('../external-system/delete');
|
|
40
|
+
await externalDelete.deleteExternalSystem(systemKey, options);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
handleCommandError(error, 'delete');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
program.command('test <app>')
|
|
48
|
+
.description('Run unit tests for external system (local validation, no API calls)')
|
|
49
|
+
.option('-d, --datasource <key>', 'Test specific datasource only')
|
|
50
|
+
.option('-v, --verbose', 'Show detailed validation output')
|
|
51
|
+
.action(async(appName, options) => {
|
|
52
|
+
try {
|
|
53
|
+
const test = require('../external-system/test');
|
|
54
|
+
const results = await test.testExternalSystem(appName, options);
|
|
55
|
+
test.displayTestResults(results, options.verbose);
|
|
56
|
+
if (!results.valid) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
handleCommandError(error, 'test');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
program.command('test-integration <app>')
|
|
66
|
+
.description('Run integration tests via dataplane pipeline API')
|
|
67
|
+
.option('-d, --datasource <key>', 'Test specific datasource only')
|
|
68
|
+
.option('-p, --payload <file>', 'Path to custom test payload file')
|
|
69
|
+
.option('-v, --verbose', 'Show detailed test output')
|
|
70
|
+
.option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
|
|
71
|
+
.action(async(appName, options) => {
|
|
72
|
+
try {
|
|
73
|
+
const test = require('../external-system/test');
|
|
74
|
+
const results = await test.testExternalSystemIntegration(appName, options);
|
|
75
|
+
test.displayIntegrationTestResults(results, options.verbose);
|
|
76
|
+
if (!results.success) {
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
handleCommandError(error, 'test-integration');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { setupExternalSystemCommands };
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI infrastructure command setup (up-infra, up-platform, up-miso, up-dataplane, down-infra, doctor, status, restart).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Infrastructure command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const infra = require('../infrastructure');
|
|
11
|
+
const appLib = require('../app');
|
|
12
|
+
const validator = require('../validation/validator');
|
|
13
|
+
const config = require('../core/config');
|
|
14
|
+
const logger = require('../utils/logger');
|
|
15
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
16
|
+
const { handleUpMiso } = require('../commands/up-miso');
|
|
17
|
+
const { handleUpDataplane } = require('../commands/up-dataplane');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Runs the up-infra command: resolves developer ID, traefik, and starts infra.
|
|
21
|
+
* @param {Object} options - Commander options (developer, traefik)
|
|
22
|
+
* @returns {Promise<void>}
|
|
23
|
+
*/
|
|
24
|
+
async function runUpInfraCommand(options) {
|
|
25
|
+
await config.ensureSecretsEncryptionKey();
|
|
26
|
+
let developerId = null;
|
|
27
|
+
if (options.developer) {
|
|
28
|
+
const id = parseInt(options.developer, 10);
|
|
29
|
+
if (isNaN(id) || id < 0) {
|
|
30
|
+
throw new Error('Developer ID must be a non-negative number (0 = default infra, > 0 = developer-specific)');
|
|
31
|
+
}
|
|
32
|
+
await config.setDeveloperId(id);
|
|
33
|
+
process.env.AIFABRIX_DEVELOPERID = id.toString();
|
|
34
|
+
developerId = id;
|
|
35
|
+
logger.log(chalk.green(`ā Developer ID set to ${id}`));
|
|
36
|
+
}
|
|
37
|
+
const cfg = await config.getConfig();
|
|
38
|
+
if (options.traefik === true) {
|
|
39
|
+
cfg.traefik = true;
|
|
40
|
+
await config.saveConfig(cfg);
|
|
41
|
+
logger.log(chalk.green('ā Traefik enabled and saved to config'));
|
|
42
|
+
} else if (options.traefik === false) {
|
|
43
|
+
cfg.traefik = false;
|
|
44
|
+
await config.saveConfig(cfg);
|
|
45
|
+
logger.log(chalk.green('ā Traefik disabled and saved to config'));
|
|
46
|
+
}
|
|
47
|
+
const useTraefik = options.traefik === true ? true : (options.traefik === false ? false : !!(cfg.traefik));
|
|
48
|
+
await infra.startInfra(developerId, { traefik: useTraefik });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Sets up infrastructure commands
|
|
53
|
+
* @param {Command} program - Commander program instance
|
|
54
|
+
*/
|
|
55
|
+
function setupInfraCommands(program) {
|
|
56
|
+
program.command('up-infra')
|
|
57
|
+
.description('Start local infrastructure: Postgres, Redis, optional Traefik')
|
|
58
|
+
.option('-d, --developer <id>', 'Set developer ID and start infrastructure')
|
|
59
|
+
.option('--traefik', 'Include Traefik reverse proxy and save to config')
|
|
60
|
+
.option('--no-traefik', 'Exclude Traefik and save to config')
|
|
61
|
+
.action(async(options) => {
|
|
62
|
+
try {
|
|
63
|
+
await runUpInfraCommand(options);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
handleCommandError(error, 'up-infra');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
program.command('up-platform')
|
|
71
|
+
.description('Start platform (Keycloak, Miso Controller, Dataplane) from community images; infra must be up')
|
|
72
|
+
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
73
|
+
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
74
|
+
.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]))
|
|
75
|
+
.action(async(options) => {
|
|
76
|
+
try {
|
|
77
|
+
await handleUpMiso(options);
|
|
78
|
+
await handleUpDataplane(options);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
handleCommandError(error, 'up-platform');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
program.command('up-miso')
|
|
86
|
+
.description('Install keycloak, miso-controller, and dataplane from images (no build). Infra must be up. Uses auto-generated secrets for testing.')
|
|
87
|
+
.option('-r, --registry <url>', 'Override registry for all apps (e.g. myacr.azurecr.io)')
|
|
88
|
+
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
89
|
+
.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]))
|
|
90
|
+
.action(async(options) => {
|
|
91
|
+
try {
|
|
92
|
+
await handleUpMiso(options);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
handleCommandError(error, 'up-miso');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
program.command('up-dataplane')
|
|
100
|
+
.description('Register and deploy dataplane app in dev (requires login, environment must be dev)')
|
|
101
|
+
.option('-r, --registry <url>', 'Override registry for dataplane image')
|
|
102
|
+
.option('--registry-mode <mode>', 'Override registry mode (acr|external)')
|
|
103
|
+
.option('-i, --image <ref>', 'Override dataplane image reference (e.g. myreg/dataplane:latest)')
|
|
104
|
+
.action(async(options) => {
|
|
105
|
+
try {
|
|
106
|
+
await handleUpDataplane(options);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
handleCommandError(error, 'up-dataplane');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
program.command('down-infra [app]')
|
|
114
|
+
.description('Stop and remove local infrastructure services or a specific application')
|
|
115
|
+
.option('-v, --volumes', 'Remove volumes (deletes all data)')
|
|
116
|
+
.action(async(appName, options) => {
|
|
117
|
+
try {
|
|
118
|
+
if (typeof appName === 'string' && appName.trim().length > 0) {
|
|
119
|
+
await appLib.downApp(appName, { volumes: !!options.volumes });
|
|
120
|
+
} else {
|
|
121
|
+
if (options.volumes) {
|
|
122
|
+
await infra.stopInfraWithVolumes();
|
|
123
|
+
} else {
|
|
124
|
+
await infra.stopInfra();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
handleCommandError(error, 'down-infra');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
program.command('doctor')
|
|
134
|
+
.description('Check environment and configuration')
|
|
135
|
+
.action(async() => {
|
|
136
|
+
try {
|
|
137
|
+
const result = await validator.checkEnvironment();
|
|
138
|
+
logger.log('\nš AI Fabrix Environment Check\n');
|
|
139
|
+
|
|
140
|
+
logger.log(`Docker: ${result.docker === 'ok' ? 'ā
Running' : 'ā Not available'}`);
|
|
141
|
+
logger.log(`Ports: ${result.ports === 'ok' ? 'ā
Available' : 'ā ļø Some ports in use'}`);
|
|
142
|
+
logger.log(`Secrets: ${result.secrets === 'ok' ? 'ā
Configured' : 'ā Missing'}`);
|
|
143
|
+
|
|
144
|
+
if (result.recommendations.length > 0) {
|
|
145
|
+
logger.log('\nš Recommendations:');
|
|
146
|
+
result.recommendations.forEach(rec => logger.log(` ⢠${rec}`));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (result.docker === 'ok') {
|
|
150
|
+
try {
|
|
151
|
+
const health = await infra.checkInfraHealth();
|
|
152
|
+
logger.log('\nš„ Infrastructure Health:');
|
|
153
|
+
Object.entries(health).forEach(([service, status]) => {
|
|
154
|
+
const icon = status === 'healthy' ? 'ā
' : status === 'unknown' ? 'ā' : 'ā';
|
|
155
|
+
logger.log(` ${icon} ${service}: ${status}`);
|
|
156
|
+
});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
logger.log('\nš„ Infrastructure: Not running');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
logger.log('');
|
|
163
|
+
} catch (error) {
|
|
164
|
+
handleCommandError(error, 'doctor');
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
program.command('status')
|
|
170
|
+
.description('Show detailed infrastructure service status and running applications')
|
|
171
|
+
.action(async() => {
|
|
172
|
+
try {
|
|
173
|
+
const status = await infra.getInfraStatus();
|
|
174
|
+
logger.log('\nš Infrastructure Status\n');
|
|
175
|
+
|
|
176
|
+
Object.entries(status).forEach(([service, info]) => {
|
|
177
|
+
const normalizedStatus = String(info.status).trim().toLowerCase();
|
|
178
|
+
const icon = normalizedStatus === 'running' ? 'ā
' : 'ā';
|
|
179
|
+
logger.log(`${icon} ${service}:`);
|
|
180
|
+
logger.log(` Status: ${info.status}`);
|
|
181
|
+
logger.log(` Port: ${info.port}`);
|
|
182
|
+
logger.log(` URL: ${info.url}`);
|
|
183
|
+
logger.log('');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const apps = await infra.getAppStatus();
|
|
187
|
+
if (apps.length > 0) {
|
|
188
|
+
logger.log('š± Running Applications\n');
|
|
189
|
+
apps.forEach((appInfo) => {
|
|
190
|
+
const normalizedStatus = String(appInfo.status).trim().toLowerCase();
|
|
191
|
+
const icon = normalizedStatus.includes('running') || normalizedStatus.includes('up') ? 'ā
' : 'ā';
|
|
192
|
+
logger.log(`${icon} ${appInfo.name}:`);
|
|
193
|
+
logger.log(` Container: ${appInfo.container}`);
|
|
194
|
+
logger.log(` Port: ${appInfo.port}`);
|
|
195
|
+
logger.log(` Status: ${appInfo.status}`);
|
|
196
|
+
logger.log(` URL: ${appInfo.url}`);
|
|
197
|
+
logger.log('');
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
handleCommandError(error, 'status');
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
program.command('restart <service>')
|
|
207
|
+
.description('Restart a specific infrastructure service')
|
|
208
|
+
.action(async(service) => {
|
|
209
|
+
try {
|
|
210
|
+
await infra.restartService(service);
|
|
211
|
+
logger.log(`ā
${service} service restarted successfully`);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
handleCommandError(error, 'restart');
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = { setupInfraCommands };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI secrets and security command setup (secrets set, secure).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Secrets command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { handleSecretsSet } = require('../commands/secrets-set');
|
|
11
|
+
const { handleSecure } = require('../commands/secure');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Sets up secrets and security commands
|
|
15
|
+
* @param {Command} program - Commander program instance
|
|
16
|
+
*/
|
|
17
|
+
function setupSecretsCommands(program) {
|
|
18
|
+
const secretsCmd = program
|
|
19
|
+
.command('secrets')
|
|
20
|
+
.description('Manage secrets in secrets files');
|
|
21
|
+
|
|
22
|
+
secretsCmd
|
|
23
|
+
.command('set <key> <value>')
|
|
24
|
+
.description('Set a secret value in secrets file')
|
|
25
|
+
.option('--shared', 'Save to general secrets file (from config.yaml aifabrix-secrets) instead of user secrets')
|
|
26
|
+
.action(async(key, value, options) => {
|
|
27
|
+
try {
|
|
28
|
+
await handleSecretsSet(key, value, options);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
handleCommandError(error, 'secrets set');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
program.command('secure')
|
|
36
|
+
.description('Encrypt secrets in secrets.local.yaml files for ISO 27001 compliance')
|
|
37
|
+
.option('--secrets-encryption <key>', 'Encryption key (32 bytes, hex or base64)')
|
|
38
|
+
.action(async(options) => {
|
|
39
|
+
try {
|
|
40
|
+
await handleSecure(options);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
handleCommandError(error, 'secure');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { setupSecretsCommands };
|