ante-erp-cli 1.11.31 → 1.11.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ante-erp-cli",
3
- "version": "1.11.31",
3
+ "version": "1.11.33",
4
4
  "description": "Comprehensive CLI tool for managing ANTE ERP self-hosted installations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,7 @@ import { fileURLToPath } from 'url';
10
10
  import { runSystemChecks, checkAndInstallDocker } from '../utils/validation.js';
11
11
  import { generateCredentials } from '../utils/password.js';
12
12
  import { saveInstallConfig, detectInstallation } from '../utils/config.js';
13
- import { pullImagesSilent, startServicesSilent, waitForServiceHealthy, runMigrations } from '../utils/docker.js';
13
+ import { pullImagesSilent, startServicesSilent, waitForServiceHealthy, runMigrations, downServices } from '../utils/docker.js';
14
14
  import { generateDockerCompose } from '../templates/docker-compose.yml.js';
15
15
  import { generateEnv } from '../templates/env.js';
16
16
  import { detectPublicIPWithFeedback, buildURL } from '../utils/network.js';
@@ -139,55 +139,111 @@ export async function install(options) {
139
139
 
140
140
  // Check if already installed
141
141
  const existing = detectInstallation();
142
- if (existing && !options.force) {
142
+ if (existing) {
143
143
  console.log(chalk.yellow('\n⚠ ANTE is already installed\n'));
144
144
  console.log(chalk.gray('Installation directory: ') + chalk.white(existing));
145
- console.log(chalk.cyan('\n📋 What you can do:\n'));
146
- console.log(chalk.gray(' • Update existing installation: ') + chalk.white('ante update'));
147
- console.log(chalk.gray(' • Check current status: ') + chalk.white('ante status'));
148
- console.log(chalk.gray(' • Force reinstall (dangerous): ') + chalk.white('ante install --force'));
149
- console.log(chalk.gray('\nTo completely remove and reinstall:'));
150
- console.log(chalk.gray(' ') + chalk.white('ante uninstall --force && ante install\n'));
151
- console.error(chalk.red('✗ Installation aborted to prevent data loss.\n'));
152
- process.exit(1);
153
- }
154
145
 
155
- if (existing && options.force) {
156
- console.log(chalk.yellow('\n⚠️ WARNING: Force reinstall mode\n'));
157
- console.log(chalk.red('This will overwrite your existing installation at: ') + chalk.white(existing));
158
- console.log(chalk.gray('Existing .env file will be backed up automatically\n'));
159
-
160
- // Add strong warning about credential regeneration
161
- if (!options.preserveCredentials) {
162
- console.log(chalk.red('⚠️ CRITICAL WARNING:\n'));
163
- console.log(chalk.yellow('This will generate NEW database credentials!'));
164
- console.log(chalk.yellow('Your existing PostgreSQL, MongoDB, and Redis passwords will be replaced.'));
165
- console.log(chalk.yellow('This will BREAK database connections if volumes persist!\n'));
166
- console.log(chalk.cyan('To preserve existing credentials, use: ') + chalk.white('--preserve-credentials\n'));
167
-
168
- // Require interactive confirmation
169
- const { confirmReinstall } = await inquirer.prompt([
146
+ // Ask user what they want to do
147
+ const { existingAction } = await inquirer.prompt([
148
+ {
149
+ type: 'list',
150
+ name: 'existingAction',
151
+ message: 'What would you like to do?',
152
+ choices: [
153
+ {
154
+ name: 'Reinstall (clean) - Remove all data and start fresh',
155
+ value: 'reinstall-clean'
156
+ },
157
+ {
158
+ name: 'Reinstall (keep data) - Keep existing database data',
159
+ value: 'reinstall-keep'
160
+ },
161
+ {
162
+ name: 'Update - Update to latest version (recommended)',
163
+ value: 'update'
164
+ },
165
+ {
166
+ name: 'Cancel - Exit without changes',
167
+ value: 'cancel'
168
+ }
169
+ ],
170
+ default: 'reinstall-clean'
171
+ }
172
+ ]);
173
+
174
+ if (existingAction === 'cancel') {
175
+ console.log(chalk.yellow('\nInstallation cancelled.\n'));
176
+ process.exit(0);
177
+ }
178
+
179
+ if (existingAction === 'update') {
180
+ console.log(chalk.cyan('\nTo update, run: ') + chalk.white('ante update\n'));
181
+ process.exit(0);
182
+ }
183
+
184
+ // Handle reinstall options
185
+ if (existingAction === 'reinstall-clean') {
186
+ // Require confirmation for destructive action
187
+ console.log(chalk.red('\n⚠️ WARNING: This will permanently delete all data!'));
188
+ console.log(chalk.yellow(' • PostgreSQL database'));
189
+ console.log(chalk.yellow(' • MongoDB database'));
190
+ console.log(chalk.yellow(' • Redis cache'));
191
+ console.log(chalk.yellow(' • Uploaded files\n'));
192
+
193
+ const { confirmDelete } = await inquirer.prompt([
170
194
  {
171
195
  type: 'input',
172
- name: 'confirmReinstall',
173
- message: 'Type "reinstall-and-reset-credentials" to confirm:',
196
+ name: 'confirmDelete',
197
+ message: chalk.red('Type "DELETE ALL DATA" to confirm:'),
174
198
  validate: (input) => {
175
- if (input === 'reinstall-and-reset-credentials') {
176
- return true;
177
- }
199
+ if (input === 'DELETE ALL DATA') return true;
178
200
  return 'You must type the exact phrase to continue';
179
201
  }
180
202
  }
181
203
  ]);
182
204
 
183
- if (confirmReinstall !== 'reinstall-and-reset-credentials') {
184
- console.error(chalk.red('\n✗ Installation cancelled.\n'));
185
- process.exit(1);
205
+ if (confirmDelete !== 'DELETE ALL DATA') {
206
+ console.log(chalk.yellow('\nInstallation cancelled.\n'));
207
+ process.exit(0);
186
208
  }
187
209
 
188
- console.log(chalk.green('\n✓ Confirmation received. Proceeding with force reinstall...\n'));
189
- } else {
190
- console.log(chalk.green('✓ Preserving existing credentials from .env file\n'));
210
+ // Stop services and remove volumes
211
+ const composeFile = join(existing, 'docker-compose.yml');
212
+ if (existsSync(composeFile)) {
213
+ console.log(chalk.yellow('\nStopping services and removing volumes...'));
214
+ try {
215
+ await downServices(composeFile, true); // true = remove volumes
216
+ console.log(chalk.green('✓ Cleanup complete\n'));
217
+ } catch (error) {
218
+ console.log(chalk.yellow(`⚠ Cleanup warning: ${error.message}`));
219
+ console.log(chalk.gray('Continuing with installation...\n'));
220
+ }
221
+ }
222
+ } else if (existingAction === 'reinstall-keep') {
223
+ console.log(chalk.yellow('\n⚠ Keeping existing data.'));
224
+ console.log(chalk.yellow(' If installation fails due to credential mismatch, reinstall with cleanup.\n'));
225
+
226
+ // Stop services but keep volumes
227
+ const composeFile = join(existing, 'docker-compose.yml');
228
+ if (existsSync(composeFile)) {
229
+ console.log(chalk.yellow('Stopping existing services...'));
230
+ try {
231
+ await downServices(composeFile, false); // false = keep volumes
232
+ console.log(chalk.green('✓ Services stopped\n'));
233
+ } catch (error) {
234
+ console.log(chalk.yellow(`⚠ Warning: ${error.message}`));
235
+ console.log(chalk.gray('Continuing with installation...\n'));
236
+ }
237
+ }
238
+ }
239
+
240
+ // Backup existing .env
241
+ const envPath = join(existing, '.env');
242
+ if (existsSync(envPath)) {
243
+ const backupPath = backupEnvFile(envPath);
244
+ if (backupPath) {
245
+ console.log(chalk.yellow(`⚠ Existing config backed up: ${backupPath}\n`));
246
+ }
191
247
  }
192
248
  }
193
249