@openfactu/cli 0.0.7 → 0.0.8

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.
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerDoctorCommand(program: Command): void;
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerDoctorCommand = registerDoctorCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const child_process_1 = require("child_process");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const paths_1 = require("../utils/paths");
13
+ const helpers_1 = require("../utils/helpers");
14
+ function registerDoctorCommand(program) {
15
+ program
16
+ .command('doctor')
17
+ .description('Diagnostico completo del entorno OpenFactu')
18
+ .option('--path <path>', 'Ruta del proyecto')
19
+ .option('--json', 'Salida en formato JSON')
20
+ .action(async (opts) => {
21
+ console.log();
22
+ console.log(chalk_1.default.bold.white(' OpenFactu — Doctor'));
23
+ console.log(chalk_1.default.dim(' ────────────────────────────────────'));
24
+ console.log();
25
+ const checks = [];
26
+ // System info
27
+ checks.push({
28
+ category: 'Sistema',
29
+ name: 'Plataforma',
30
+ status: 'ok',
31
+ message: `${os_1.default.type()} ${os_1.default.release()} (${os_1.default.arch()})`,
32
+ });
33
+ checks.push({
34
+ category: 'Sistema',
35
+ name: 'Node.js',
36
+ status: 'ok',
37
+ message: process.version,
38
+ });
39
+ checks.push({
40
+ category: 'Sistema',
41
+ name: 'Memoria total',
42
+ status: 'ok',
43
+ message: (0, helpers_1.formatBytes)(os_1.default.totalmem()),
44
+ });
45
+ checks.push({
46
+ category: 'Sistema',
47
+ name: 'Memoria libre',
48
+ status: 'ok',
49
+ message: (0, helpers_1.formatBytes)(os_1.default.freemem()),
50
+ });
51
+ // Preflight checks
52
+ const root = opts.path || process.cwd();
53
+ const preflight = (0, helpers_1.runPreflightChecks)(root);
54
+ for (const check of preflight) {
55
+ checks.push({
56
+ category: 'Requisitos',
57
+ name: check.name,
58
+ status: check.status === 'pass' ? 'ok' : check.status === 'warn' ? 'warn' : 'error',
59
+ message: check.message,
60
+ });
61
+ }
62
+ // Project structure
63
+ try {
64
+ const projectRoot = (0, paths_1.getProjectRoot)();
65
+ checks.push({
66
+ category: 'Proyecto',
67
+ name: 'Raiz detectada',
68
+ status: 'ok',
69
+ message: projectRoot,
70
+ });
71
+ // Check key files
72
+ const keyFiles = [
73
+ { path: 'package.json', name: 'package.json' },
74
+ { path: 'docker-compose.yml', name: 'docker-compose.yml' },
75
+ { path: '.env', name: '.env' },
76
+ { path: 'apps/web', name: 'apps/web' },
77
+ { path: 'apps/server', name: 'apps/server' },
78
+ ];
79
+ for (const file of keyFiles) {
80
+ const fullPath = path_1.default.join(projectRoot, file.path);
81
+ const exists = fs_1.default.existsSync(fullPath);
82
+ checks.push({
83
+ category: 'Proyecto',
84
+ name: file.name,
85
+ status: exists ? 'ok' : 'warn',
86
+ message: exists ? 'Presente' : 'No encontrado',
87
+ });
88
+ }
89
+ // Disk usage
90
+ const diskUsage = (0, child_process_1.execSync)(`du -sh "${projectRoot}" 2>/dev/null | cut -f1`, { stdio: 'pipe' }).toString().trim();
91
+ checks.push({
92
+ category: 'Proyecto',
93
+ name: 'Tamano del proyecto',
94
+ status: 'ok',
95
+ message: diskUsage,
96
+ });
97
+ // Disk space available
98
+ const disk = (0, helpers_1.checkDiskSpace)(projectRoot);
99
+ checks.push({
100
+ category: 'Proyecto',
101
+ name: 'Espacio disponible',
102
+ status: disk.availableGB >= 10 ? 'ok' : disk.availableGB >= 5 ? 'warn' : 'error',
103
+ message: `${disk.availableGB}GB libres de ${disk.totalGB}GB`,
104
+ });
105
+ }
106
+ catch (err) {
107
+ checks.push({
108
+ category: 'Proyecto',
109
+ name: 'Raiz del proyecto',
110
+ status: 'error',
111
+ message: 'No detectado',
112
+ });
113
+ }
114
+ // Docker status
115
+ try {
116
+ const dockerCmd = (0, helpers_1.getDockerComposeCommand)();
117
+ const dockerInfo = (0, child_process_1.execSync)('docker info --format "{{.ServerVersion}}" 2>/dev/null || echo "unknown"', {
118
+ stdio: 'pipe',
119
+ }).toString().trim();
120
+ checks.push({
121
+ category: 'Docker',
122
+ name: 'Version del servidor',
123
+ status: 'ok',
124
+ message: dockerInfo,
125
+ });
126
+ // Running containers
127
+ const runningContainers = (0, child_process_1.execSync)('docker ps --format "{{.Names}}" 2>/dev/null || true', {
128
+ stdio: 'pipe',
129
+ }).toString().trim();
130
+ const containerList = runningContainers ? runningContainers.split('\n') : [];
131
+ checks.push({
132
+ category: 'Docker',
133
+ name: 'Contenedores corriendo',
134
+ status: containerList.length > 0 ? 'ok' : 'warn',
135
+ message: containerList.length > 0 ? containerList.join(', ') : 'Ninguno',
136
+ });
137
+ // Docker images
138
+ const imageCount = (0, child_process_1.execSync)('docker images --format "{{.ID}}" 2>/dev/null | wc -l', {
139
+ stdio: 'pipe',
140
+ }).toString().trim();
141
+ const dockerDisk = (0, child_process_1.execSync)('docker system df --format "{{.Size}}" 2>/dev/null | head -1 || echo "unknown"', {
142
+ stdio: 'pipe',
143
+ }).toString().trim();
144
+ checks.push({
145
+ category: 'Docker',
146
+ name: 'Imagenes',
147
+ status: 'ok',
148
+ message: `${imageCount} imagenes, ${dockerDisk} en disco`,
149
+ });
150
+ // Docker networks
151
+ const networks = (0, child_process_1.execSync)('docker network ls --format "{{.Name}}" 2>/dev/null | grep openfactu || true', {
152
+ stdio: 'pipe',
153
+ }).toString().trim();
154
+ checks.push({
155
+ category: 'Docker',
156
+ name: 'Redes OpenFactu',
157
+ status: networks ? 'ok' : 'warn',
158
+ message: networks || 'Ninguna detectada',
159
+ });
160
+ // Docker volumes
161
+ const volumes = (0, child_process_1.execSync)('docker volume ls --format "{{.Name}}" 2>/dev/null | grep openfactu || true', {
162
+ stdio: 'pipe',
163
+ }).toString().trim();
164
+ checks.push({
165
+ category: 'Docker',
166
+ name: 'Volumenes OpenFactu',
167
+ status: volumes ? 'ok' : 'warn',
168
+ message: volumes || 'Ninguno detectado',
169
+ });
170
+ }
171
+ catch (err) {
172
+ checks.push({
173
+ category: 'Docker',
174
+ name: 'Estado',
175
+ status: 'error',
176
+ message: err.message,
177
+ });
178
+ }
179
+ // Services status
180
+ try {
181
+ const projectRoot = (0, paths_1.getProjectRoot)();
182
+ const dockerCmd = (0, helpers_1.getDockerComposeCommand)();
183
+ const composeFiles = [
184
+ 'docker-compose.prod.yml',
185
+ 'docker-compose.yml',
186
+ ];
187
+ for (const composeFile of composeFiles) {
188
+ const composePath = path_1.default.join(projectRoot, composeFile);
189
+ if (fs_1.default.existsSync(composePath)) {
190
+ try {
191
+ const psOutput = (0, child_process_1.execSync)(`${dockerCmd} -f ${composeFile} ps --format json 2>/dev/null || true`, {
192
+ cwd: projectRoot,
193
+ stdio: 'pipe',
194
+ }).toString().trim();
195
+ if (psOutput) {
196
+ const services = psOutput.split('\n').filter(Boolean);
197
+ checks.push({
198
+ category: 'Servicios',
199
+ name: composeFile,
200
+ status: 'ok',
201
+ message: `${services.length} servicios definidos`,
202
+ });
203
+ }
204
+ }
205
+ catch {
206
+ checks.push({
207
+ category: 'Servicios',
208
+ name: composeFile,
209
+ status: 'warn',
210
+ message: 'No se pudo obtener estado',
211
+ });
212
+ }
213
+ }
214
+ }
215
+ }
216
+ catch { }
217
+ // Systemd services
218
+ try {
219
+ const services = (0, child_process_1.execSync)('systemctl list-units --type=service --state=running 2>/dev/null | grep openfactu || true', {
220
+ stdio: 'pipe',
221
+ }).toString().trim();
222
+ if (services) {
223
+ checks.push({
224
+ category: 'Systemd',
225
+ name: 'Servicios activos',
226
+ status: 'ok',
227
+ message: services,
228
+ });
229
+ }
230
+ }
231
+ catch { }
232
+ // Git status
233
+ try {
234
+ const projectRoot = (0, paths_1.getProjectRoot)();
235
+ if (fs_1.default.existsSync(path_1.default.join(projectRoot, '.git'))) {
236
+ const branch = (0, child_process_1.execSync)('git branch --show-current 2>/dev/null || echo "detached"', {
237
+ cwd: projectRoot,
238
+ stdio: 'pipe',
239
+ }).toString().trim();
240
+ const status = (0, child_process_1.execSync)('git status --porcelain 2>/dev/null | wc -l', {
241
+ cwd: projectRoot,
242
+ stdio: 'pipe',
243
+ }).toString().trim();
244
+ checks.push({
245
+ category: 'Git',
246
+ name: 'Branch',
247
+ status: 'ok',
248
+ message: branch,
249
+ });
250
+ checks.push({
251
+ category: 'Git',
252
+ name: 'Cambios locales',
253
+ status: parseInt(status) === 0 ? 'ok' : 'warn',
254
+ message: parseInt(status) === 0 ? 'Limpio' : `${status} archivos modificados`,
255
+ });
256
+ }
257
+ }
258
+ catch { }
259
+ // Display results
260
+ if (opts.json) {
261
+ console.log(JSON.stringify(checks, null, 2));
262
+ return;
263
+ }
264
+ const categories = [...new Set(checks.map(c => c.category))];
265
+ for (const category of categories) {
266
+ const categoryChecks = checks.filter(c => c.category === category);
267
+ console.log(chalk_1.default.bold(` ${category}`));
268
+ console.log(chalk_1.default.dim(' ' + '─'.repeat(50)));
269
+ for (const check of categoryChecks) {
270
+ const icon = check.status === 'ok'
271
+ ? chalk_1.default.green('✓')
272
+ : check.status === 'warn'
273
+ ? chalk_1.default.yellow('⚠')
274
+ : chalk_1.default.red('✗');
275
+ console.log(` ${icon} ${chalk_1.default.dim(check.name.padEnd(25))} ${check.message}`);
276
+ }
277
+ console.log();
278
+ }
279
+ // Summary
280
+ const errors = checks.filter(c => c.status === 'error');
281
+ const warns = checks.filter(c => c.status === 'warn');
282
+ if (errors.length === 0 && warns.length === 0) {
283
+ console.log(chalk_1.default.bold.green(' Todo esta correcto'));
284
+ }
285
+ else {
286
+ if (errors.length > 0) {
287
+ console.log(chalk_1.default.bold.red(` ${errors.length} error(es) encontrado(s)`));
288
+ }
289
+ if (warns.length > 0) {
290
+ console.log(chalk_1.default.bold.yellow(` ${warns.length} advertencia(s)`));
291
+ }
292
+ }
293
+ console.log();
294
+ });
295
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerInstallQuickCommand(program: Command): void;
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerInstallQuickCommand = registerInstallQuickCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const child_process_1 = require("child_process");
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const os_1 = __importDefault(require("os"));
14
+ const logger_1 = require("../utils/logger");
15
+ const helpers_1 = require("../utils/helpers");
16
+ const REPO_URL = 'https://github.com/OpenFactu/platform.git';
17
+ function registerInstallQuickCommand(program) {
18
+ program
19
+ .command('install:quick')
20
+ .description('Instalacion rapida de OpenFactu (non-interactive)')
21
+ .option('--tag <tag>', 'Version especifica', 'latest')
22
+ .option('--dir <dir>', 'Directorio de instalacion')
23
+ .option('--no-docker', 'No levantar Docker')
24
+ .option('--monitoring', 'Incluir monitoreo')
25
+ .option('--analytics', 'Incluir analitica completa')
26
+ .option('--service', 'Instalar como servicio systemd')
27
+ .option('--generate-env', 'Generar .env con credenciales seguras')
28
+ .action(async (opts) => {
29
+ console.log();
30
+ console.log(chalk_1.default.bold.white(' OpenFactu — Instalacion Rapida'));
31
+ console.log(chalk_1.default.dim(' ────────────────────────────────────'));
32
+ console.log();
33
+ try {
34
+ let targetDir = opts.dir || path_1.default.join(os_1.default.homedir(), 'openfactu');
35
+ const dockerCmd = (0, helpers_1.getDockerComposeCommand)();
36
+ // Check Docker
37
+ const hasDocker = (() => {
38
+ try {
39
+ (0, child_process_1.execSync)('docker --version', { stdio: 'pipe' });
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ })();
46
+ if (!hasDocker && opts.docker !== false) {
47
+ logger_1.log.error('Docker es requerido para la instalacion rapida');
48
+ logger_1.log.dim(' Instala Docker: https://docs.docker.com/get-docker/');
49
+ return;
50
+ }
51
+ // Clone
52
+ const cloneSpinner = (0, ora_1.default)('Clonando repositorio...').start();
53
+ let ref = opts.tag;
54
+ if (ref === 'latest') {
55
+ try {
56
+ const releases = JSON.parse((0, child_process_1.execSync)('curl -s https://api.github.com/repos/OpenFactu/platform/releases | head -100', { stdio: 'pipe' }).toString());
57
+ const stable = releases.filter((r) => !r.prerelease && !r.draft);
58
+ if (stable.length > 0) {
59
+ ref = stable[0].tag_name;
60
+ }
61
+ else {
62
+ ref = 'main';
63
+ }
64
+ }
65
+ catch {
66
+ ref = 'main';
67
+ }
68
+ }
69
+ const isTag = ref.startsWith('v');
70
+ // Verificar si el directorio ya existe
71
+ if (fs_1.default.existsSync(targetDir)) {
72
+ const contents = fs_1.default.readdirSync(targetDir);
73
+ if (contents.length > 0) {
74
+ logger_1.log.warn(`El directorio ${targetDir} ya existe y no esta vacio`);
75
+ const { action } = await inquirer_1.default.prompt([
76
+ {
77
+ type: 'list',
78
+ name: 'action',
79
+ message: 'Que quieres hacer?',
80
+ choices: [
81
+ { name: 'Sobrescribir (eliminar y reinstalar)', value: 'overwrite' },
82
+ { name: 'Usar directorio existente (solo configurar)', value: 'reuse' },
83
+ { name: 'Elegir otro directorio', value: 'newdir' },
84
+ { name: 'Cancelar', value: 'cancel' },
85
+ ],
86
+ },
87
+ ]);
88
+ if (action === 'cancel') {
89
+ logger_1.log.info('Instalacion cancelada');
90
+ return;
91
+ }
92
+ if (action === 'overwrite') {
93
+ const removeSpinner = (0, ora_1.default)('Limpiando directorio...').start();
94
+ (0, child_process_1.execSync)(`rm -rf "${targetDir}"`, { stdio: 'pipe' });
95
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
96
+ removeSpinner.succeed('Directorio limpiado');
97
+ }
98
+ if (action === 'newdir') {
99
+ const { newDir } = await inquirer_1.default.prompt([
100
+ { type: 'input', name: 'newDir', message: 'Nuevo directorio:', default: path_1.default.join(os_1.default.homedir(), 'openfactu-2') },
101
+ ]);
102
+ targetDir = path_1.default.resolve(newDir);
103
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
104
+ }
105
+ if (action === 'reuse') {
106
+ logger_1.log.info('Usando directorio existente');
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
112
+ }
113
+ const cloneCmd = isTag
114
+ ? `git clone --depth 1 --branch ${ref} ${REPO_URL} "${targetDir}"`
115
+ : `git clone --branch ${ref} ${REPO_URL} "${targetDir}"`;
116
+ try {
117
+ (0, child_process_1.execSync)(cloneCmd, { stdio: 'pipe', timeout: 120000 });
118
+ cloneSpinner.succeed('Repositorio clonado');
119
+ }
120
+ catch (err) {
121
+ if (err.message?.includes('ya existe') || err.message?.includes('already exists')) {
122
+ cloneSpinner.warn('Directorio ya existe, usando existente');
123
+ }
124
+ else {
125
+ cloneSpinner.fail('Error al clonar: ' + err.message);
126
+ return;
127
+ }
128
+ }
129
+ // Generate .env
130
+ if (opts.generateEnv) {
131
+ const envSpinner = (0, ora_1.default)('Generando configuracion...').start();
132
+ const dbPassword = (0, helpers_1.generatePassword)(24);
133
+ const jwtSecret = (0, helpers_1.generatePassword)(48);
134
+ const envContent = `POSTGRES_USER=openfactu
135
+ POSTGRES_PASSWORD=${dbPassword}
136
+ POSTGRES_DB=openfactudb
137
+ DATABASE_URL=postgresql://openfactu:${encodeURIComponent(dbPassword)}@db:5432/openfactudb
138
+ SERVER_PORT=3000
139
+ WEB_PORT=8080
140
+ DB_PORT=5432
141
+ JWT_SECRET=${jwtSecret}
142
+ SESSION_SECRET=${(0, helpers_1.generatePassword)(32)}
143
+ NODE_ENV=production
144
+ HOST=localhost
145
+ CORS_ORIGIN=http://localhost:8080
146
+ VITE_API_URL=http://localhost:3000
147
+ ADMIN_EMAIL=admin@openfactu.local
148
+ ADMIN_PASSWORD=${(0, helpers_1.generatePassword)(16)}
149
+ `;
150
+ fs_1.default.writeFileSync(path_1.default.join(targetDir, '.env'), envContent);
151
+ envSpinner.succeed('.env generado');
152
+ logger_1.log.blank();
153
+ logger_1.log.info(`${chalk_1.default.dim('Admin:')} admin@openfactu.local / ${chalk_1.default.yellow('ver .env')}`);
154
+ logger_1.log.blank();
155
+ }
156
+ else {
157
+ const envExample = path_1.default.join(targetDir, '.env.example');
158
+ const envFile = path_1.default.join(targetDir, '.env');
159
+ if (fs_1.default.existsSync(envExample) && !fs_1.default.existsSync(envFile)) {
160
+ fs_1.default.copyFileSync(envExample, envFile);
161
+ }
162
+ }
163
+ // Docker build and up
164
+ if (opts.docker !== false) {
165
+ const buildSpinner = (0, ora_1.default)('Construyendo contenedores...').start();
166
+ try {
167
+ (0, child_process_1.execSync)(`${dockerCmd} build`, { cwd: targetDir, stdio: 'pipe', timeout: 300000 });
168
+ buildSpinner.succeed('Contenedores construidos');
169
+ }
170
+ catch (err) {
171
+ buildSpinner.fail('Error en build');
172
+ logger_1.log.dim(` cd ${targetDir} && ${dockerCmd} build`);
173
+ }
174
+ const upSpinner = (0, ora_1.default)('Levantando servicios...').start();
175
+ try {
176
+ let composeFlags = '-f docker-compose.yml';
177
+ if (fs_1.default.existsSync(path_1.default.join(targetDir, 'docker-compose.prod.yml'))) {
178
+ composeFlags = '-f docker-compose.prod.yml';
179
+ }
180
+ if (opts.monitoring) {
181
+ const monPath = path_1.default.join(targetDir, 'docker-compose.monitoring.yml');
182
+ if (fs_1.default.existsSync(monPath)) {
183
+ composeFlags += ' -f docker-compose.monitoring.yml';
184
+ }
185
+ }
186
+ (0, child_process_1.execSync)(`${dockerCmd} ${composeFlags} up -d`, {
187
+ cwd: targetDir,
188
+ stdio: 'pipe',
189
+ timeout: 120000,
190
+ });
191
+ upSpinner.succeed('Servicios levantados');
192
+ }
193
+ catch (err) {
194
+ upSpinner.fail('Error: ' + err.message);
195
+ }
196
+ }
197
+ // Install as service
198
+ if (opts.service) {
199
+ const svcSpinner = (0, ora_1.default)('Instalando servicio systemd...').start();
200
+ try {
201
+ const unitContent = `[Unit]
202
+ Description=OpenFactu ERP Platform
203
+ After=docker.service network-online.target
204
+ Requires=docker.service
205
+
206
+ [Service]
207
+ Type=oneshot
208
+ RemainAfterExit=yes
209
+ WorkingDirectory=${targetDir}
210
+ ExecStart=${dockerCmd} -f docker-compose.yml up -d
211
+ ExecStop=${dockerCmd} -f docker-compose.yml down
212
+ Restart=on-failure
213
+ RestartSec=30
214
+
215
+ [Install]
216
+ WantedBy=multi-user.target
217
+ `;
218
+ const tempPath = '/tmp/openfactu.service';
219
+ const unitPath = '/etc/systemd/system/openfactu.service';
220
+ fs_1.default.writeFileSync(tempPath, unitContent);
221
+ (0, child_process_1.execSync)(`sudo mv ${tempPath} ${unitPath}`, { stdio: 'pipe' });
222
+ (0, child_process_1.execSync)('sudo systemctl daemon-reload', { stdio: 'pipe' });
223
+ (0, child_process_1.execSync)('sudo systemctl enable openfactu', { stdio: 'pipe' });
224
+ svcSpinner.succeed('Servicio instalado');
225
+ }
226
+ catch (err) {
227
+ svcSpinner.fail('No se pudo instalar el servicio');
228
+ }
229
+ }
230
+ // Summary
231
+ logger_1.log.blank();
232
+ console.log(chalk_1.default.bold.green(' Instalacion rapida completada'));
233
+ console.log(chalk_1.default.dim(' ────────────────────────────────────'));
234
+ logger_1.log.info(`Directorio: ${chalk_1.default.cyan(targetDir)}`);
235
+ logger_1.log.info(`Version: ${chalk_1.default.cyan(ref)}`);
236
+ logger_1.log.blank();
237
+ logger_1.log.dim(' Comandos utiles:');
238
+ logger_1.log.dim(` cd ${targetDir}`);
239
+ logger_1.log.dim(' openfactu setup');
240
+ logger_1.log.dim(' openfactu deploy');
241
+ logger_1.log.dim(' openfactu doctor');
242
+ logger_1.log.blank();
243
+ }
244
+ catch (err) {
245
+ logger_1.log.error(err.message);
246
+ process.exitCode = 1;
247
+ }
248
+ });
249
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerInstallScriptCommand(program: Command): void;