@magentrix-corp/magentrix-cli 1.3.16 → 1.3.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +1166 -1166
  3. package/actions/autopublish.old.js +293 -293
  4. package/actions/config.js +182 -182
  5. package/actions/create.js +466 -466
  6. package/actions/help.js +164 -164
  7. package/actions/iris/buildStage.js +874 -874
  8. package/actions/iris/delete.js +256 -256
  9. package/actions/iris/dev.js +391 -391
  10. package/actions/iris/index.js +6 -6
  11. package/actions/iris/link.js +375 -375
  12. package/actions/iris/recover.js +268 -268
  13. package/actions/main.js +80 -80
  14. package/actions/publish.js +1420 -1420
  15. package/actions/pull.js +684 -684
  16. package/actions/setup.js +148 -148
  17. package/actions/status.js +17 -17
  18. package/actions/update.js +248 -248
  19. package/bin/magentrix.js +393 -393
  20. package/package.json +55 -55
  21. package/utils/assetPaths.js +158 -158
  22. package/utils/autopublishLock.js +77 -77
  23. package/utils/cacher.js +206 -206
  24. package/utils/cli/checkInstanceUrl.js +76 -74
  25. package/utils/cli/helpers/compare.js +282 -282
  26. package/utils/cli/helpers/ensureApiKey.js +63 -63
  27. package/utils/cli/helpers/ensureCredentials.js +68 -68
  28. package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
  29. package/utils/cli/writeRecords.js +262 -262
  30. package/utils/compare.js +135 -135
  31. package/utils/compress.js +17 -17
  32. package/utils/config.js +527 -527
  33. package/utils/debug.js +144 -144
  34. package/utils/diagnostics/testPublishLogic.js +96 -96
  35. package/utils/diff.js +49 -49
  36. package/utils/downloadAssets.js +291 -291
  37. package/utils/filetag.js +115 -115
  38. package/utils/hash.js +14 -14
  39. package/utils/iris/backup.js +411 -411
  40. package/utils/iris/builder.js +541 -541
  41. package/utils/iris/config-reader.js +664 -664
  42. package/utils/iris/deleteHelper.js +150 -150
  43. package/utils/iris/errors.js +537 -537
  44. package/utils/iris/linker.js +601 -601
  45. package/utils/iris/lock.js +360 -360
  46. package/utils/iris/validation.js +360 -360
  47. package/utils/iris/validator.js +281 -281
  48. package/utils/iris/zipper.js +248 -248
  49. package/utils/logger.js +291 -291
  50. package/utils/magentrix/api/assets.js +220 -220
  51. package/utils/magentrix/api/auth.js +107 -107
  52. package/utils/magentrix/api/createEntity.js +61 -61
  53. package/utils/magentrix/api/deleteEntity.js +55 -55
  54. package/utils/magentrix/api/iris.js +251 -251
  55. package/utils/magentrix/api/meqlQuery.js +36 -36
  56. package/utils/magentrix/api/retrieveEntity.js +86 -86
  57. package/utils/magentrix/api/updateEntity.js +66 -66
  58. package/utils/magentrix/fetch.js +168 -168
  59. package/utils/merge.js +22 -22
  60. package/utils/permissionError.js +70 -70
  61. package/utils/preferences.js +40 -40
  62. package/utils/progress.js +469 -469
  63. package/utils/spinner.js +43 -43
  64. package/utils/template.js +52 -52
  65. package/utils/updateFileBase.js +121 -121
  66. package/utils/workspaces.js +108 -108
  67. package/vars/config.js +11 -11
  68. package/vars/global.js +50 -50
@@ -1,256 +1,256 @@
1
- import chalk from 'chalk';
2
- import { select, input, confirm } from '@inquirer/prompts';
3
- import path from 'path';
4
- import Config from '../../utils/config.js';
5
- import { ensureValidCredentials } from '../../utils/cli/helpers/ensureCredentials.js';
6
- import { backupIrisApp } from '../../utils/iris/backup.js';
7
- import { getLinkedProjects, unlinkVueProject } from '../../utils/iris/linker.js';
8
- import { deleteIrisAppFromServer, deleteLocalIrisAppFiles } from '../../utils/iris/deleteHelper.js';
9
- import { showPermissionError } from '../../utils/permissionError.js';
10
- import { EXPORT_ROOT, IRIS_APPS_DIR } from '../../vars/global.js';
11
- import { acquireLock, releaseLock, LockTypes } from '../../utils/iris/lock.js';
12
- import { formatFileLockError } from '../../utils/iris/errors.js';
13
-
14
- const config = new Config();
15
-
16
- /**
17
- * iris-app-delete command - Delete a published Iris app with backup and recovery.
18
- */
19
- export const irisDelete = async () => {
20
- process.stdout.write('\x1Bc'); // Clear console
21
-
22
- console.log(chalk.red.bold('\n⚠ Delete Iris App'));
23
- console.log(chalk.gray('─'.repeat(48)));
24
- console.log();
25
-
26
- // Get list of published apps from base.json
27
- const cachedResults = config.read(null, { filename: "base.json" });
28
- const cachedIrisApps = Object.values(cachedResults || {})
29
- .filter(entry => entry.type === 'IrisApp' || entry.Type === 'IrisApp')
30
- .map(entry => {
31
- const slug = entry.folderName || (entry.recordId && entry.recordId.startsWith('iris-app:')
32
- ? entry.recordId.replace('iris-app:', '')
33
- : null);
34
- return {
35
- slug,
36
- appName: entry.appName || slug,
37
- folderName: entry.folderName || slug
38
- };
39
- })
40
- .filter(app => app.slug);
41
-
42
- if (cachedIrisApps.length === 0) {
43
- console.log(chalk.yellow('No published Iris apps found.'));
44
- console.log();
45
- console.log(chalk.gray('Published apps appear here after running:'));
46
- console.log(chalk.white(` 1. ${chalk.cyan('magentrix vue-run-build')}`));
47
- console.log(chalk.white(` 2. ${chalk.cyan('magentrix publish')}`));
48
- console.log();
49
- return;
50
- }
51
-
52
- // Build choices
53
- const choices = cachedIrisApps.map(app => ({
54
- name: `${app.appName} (${app.slug})`,
55
- value: app
56
- }));
57
-
58
- choices.push({
59
- name: 'Cancel',
60
- value: null
61
- });
62
-
63
- // Select app to delete
64
- const selectedApp = await select({
65
- message: 'Which Iris app do you want to delete?',
66
- choices
67
- });
68
-
69
- if (!selectedApp) {
70
- console.log(chalk.gray('Cancelled.'));
71
- return;
72
- }
73
-
74
- const { slug, appName } = selectedApp;
75
-
76
- // Show destructive warning
77
- console.log();
78
- console.log(chalk.bgRed.bold.white(' ⚠ DESTRUCTIVE OPERATION '));
79
- console.log(chalk.red('─'.repeat(48)));
80
- console.log(chalk.white('This will permanently delete:'));
81
- console.log(chalk.red(` • App from server: ${chalk.cyan(appName)} (${slug})`));
82
- console.log(chalk.red(` • Local files: ${chalk.gray(`src/iris-apps/${slug}/`)}`));
83
- console.log(chalk.red(` • Navigation menu entry on Magentrix`));
84
- console.log();
85
- console.log(chalk.yellow('A recovery backup will be created before deletion.'));
86
- console.log(chalk.gray('You can restore using: ') + chalk.cyan('magentrix iris-app-recover'));
87
- console.log(chalk.red('─'.repeat(48)));
88
- console.log();
89
-
90
- // Confirm deletion by typing app name
91
- const confirmation = await input({
92
- message: `Type the app slug "${slug}" to confirm deletion:`,
93
- validate: (value) => {
94
- if (value === slug) return true;
95
- return `Please type exactly: ${slug}`;
96
- }
97
- });
98
-
99
- if (confirmation !== slug) {
100
- console.log(chalk.gray('Cancelled.'));
101
- return;
102
- }
103
-
104
- // Acquire delete lock to prevent concurrent deletions
105
- const lockBasePath = path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.magentrix-locks');
106
- const lockResult = acquireLock(LockTypes.DELETE, {
107
- context: slug,
108
- operation: `deleting ${slug}`,
109
- basePath: lockBasePath
110
- });
111
-
112
- // Track if lock was acquired (permission errors are non-fatal for delete)
113
- let lockAcquired = lockResult.acquired;
114
- if (!lockResult.acquired) {
115
- if (lockResult.error?.includes('permission') || lockResult.error?.includes('EACCES')) {
116
- console.log(chalk.yellow('Warning: Could not create delete lock (permission issue). Proceeding without lock.'));
117
- lockAcquired = false;
118
- } else {
119
- console.log(chalk.red('Cannot delete app:'));
120
- console.log(chalk.yellow(lockResult.error));
121
- return;
122
- }
123
- }
124
-
125
- try {
126
- await performDelete(slug, appName);
127
- } finally {
128
- if (lockAcquired) {
129
- releaseLock(LockTypes.DELETE, { context: slug, basePath: lockBasePath });
130
- }
131
- }
132
- };
133
-
134
- /**
135
- * Perform the actual delete operation.
136
- * @param {string} slug - App slug
137
- * @param {string} appName - App display name
138
- */
139
- async function performDelete(slug, appName) {
140
- // Check if app is linked
141
- const linkedProjects = getLinkedProjects();
142
- const linkedProject = linkedProjects.find(p => p.slug === slug);
143
-
144
- let shouldUnlink = false;
145
- if (linkedProject) {
146
- console.log();
147
- shouldUnlink = await confirm({
148
- message: `This app is linked to a Vue project at ${linkedProject.path}. Unlink it?`,
149
- default: false
150
- });
151
- }
152
-
153
- // Create backup
154
- console.log();
155
- console.log(chalk.blue('Creating recovery backup...'));
156
-
157
- const appPath = path.join(EXPORT_ROOT, IRIS_APPS_DIR, slug);
158
- const backupResult = await backupIrisApp(appPath, {
159
- slug,
160
- appName,
161
- linkedProject: linkedProject || null
162
- });
163
-
164
- if (!backupResult.success) {
165
- console.log(chalk.red(`Failed to create backup: ${backupResult.error}`));
166
- console.log(chalk.yellow('Deletion cancelled for safety.'));
167
- return;
168
- }
169
-
170
- console.log(chalk.green(`✓ Backup created: ${backupResult.backupPath}`));
171
-
172
- // Delete from server
173
- console.log();
174
- console.log(chalk.blue('Deleting from Magentrix server...'));
175
-
176
- const { instanceUrl, token } = await ensureValidCredentials();
177
- const deleteResult = await deleteIrisAppFromServer(instanceUrl, token.value, slug, {
178
- updateCache: true // Automatically updates base.json
179
- });
180
-
181
- if (!deleteResult.success && deleteResult.error !== 'App not found on server (already deleted)') {
182
- console.log(chalk.red(`Failed to delete from server: ${deleteResult.error}`));
183
- console.log(chalk.yellow('Backup preserved. Use ') + chalk.cyan('magentrix iris-app-recover') + chalk.yellow(' to restore.'));
184
- return;
185
- }
186
-
187
- if (deleteResult.error === 'App not found on server (already deleted)') {
188
- console.log(chalk.yellow('⚠ App not found on server (already deleted)'));
189
- } else {
190
- console.log(chalk.green('✓ Deleted from server'));
191
- }
192
-
193
- if (deleteResult.cleanedFromCache) {
194
- console.log(chalk.green('✓ Cache updated'));
195
- }
196
-
197
- // Delete local files
198
- console.log(chalk.blue('Deleting local files...'));
199
-
200
- const localDeleteResult = deleteLocalIrisAppFiles(appPath);
201
-
202
- if (localDeleteResult.success) {
203
- if (localDeleteResult.existed) {
204
- console.log(chalk.green('✓ Local files deleted'));
205
- } else {
206
- console.log(chalk.gray(' (No local files found)'));
207
- }
208
- } else if (localDeleteResult.isPermissionError) {
209
- showPermissionError({
210
- operation: 'delete',
211
- targetPath: appPath
212
- });
213
- console.log();
214
- console.log(chalk.gray('Note: The app was deleted from the server and cache.'));
215
- console.log(chalk.gray('Only local file cleanup failed.'));
216
- console.log();
217
- } else if (localDeleteResult.isFileLocked) {
218
- console.log(chalk.yellow('⚠ Could not delete local files - files are in use'));
219
- console.log(chalk.gray(localDeleteResult.error));
220
- console.log();
221
- console.log(chalk.gray('Note: The app was deleted from the server and cache.'));
222
- console.log(chalk.gray('Close any programs using these files and delete manually.'));
223
- console.log();
224
- } else {
225
- console.log(chalk.yellow(`⚠ Failed to delete local files: ${localDeleteResult.error}`));
226
- console.log(chalk.gray(`Path: ${appPath}`));
227
- console.log(chalk.white('You may need to delete manually.'));
228
- }
229
-
230
- // Unlink Vue project if requested
231
- if (shouldUnlink && linkedProject) {
232
- console.log(chalk.blue('Unlinking Vue project...'));
233
- unlinkVueProject(linkedProject.path);
234
- console.log(chalk.green('✓ Vue project unlinked'));
235
- }
236
-
237
- // Summary
238
- console.log();
239
- console.log(chalk.green('─'.repeat(48)));
240
- if (localDeleteResult.success) {
241
- console.log(chalk.green.bold('✓ Iris App Deleted Successfully!'));
242
- } else {
243
- console.log(chalk.yellow.bold('⚠ Iris App Partially Deleted'));
244
- console.log();
245
- console.log(chalk.green('✓ Deleted from server'));
246
- console.log(chalk.green('✓ Cache updated'));
247
- console.log(chalk.yellow('⚠ Local files require manual deletion'));
248
- }
249
- console.log();
250
- console.log(chalk.cyan('Recovery:'));
251
- console.log(chalk.white(` Backup saved to: ${chalk.gray(backupResult.backupPath)}`));
252
- console.log(chalk.white(` To restore, run: ${chalk.cyan('magentrix iris-app-recover')}`));
253
- console.log();
254
- }
255
-
256
- export default irisDelete;
1
+ import chalk from 'chalk';
2
+ import { select, input, confirm } from '@inquirer/prompts';
3
+ import path from 'path';
4
+ import Config from '../../utils/config.js';
5
+ import { ensureValidCredentials } from '../../utils/cli/helpers/ensureCredentials.js';
6
+ import { backupIrisApp } from '../../utils/iris/backup.js';
7
+ import { getLinkedProjects, unlinkVueProject } from '../../utils/iris/linker.js';
8
+ import { deleteIrisAppFromServer, deleteLocalIrisAppFiles } from '../../utils/iris/deleteHelper.js';
9
+ import { showPermissionError } from '../../utils/permissionError.js';
10
+ import { EXPORT_ROOT, IRIS_APPS_DIR } from '../../vars/global.js';
11
+ import { acquireLock, releaseLock, LockTypes } from '../../utils/iris/lock.js';
12
+ import { formatFileLockError } from '../../utils/iris/errors.js';
13
+
14
+ const config = new Config();
15
+
16
+ /**
17
+ * iris-app-delete command - Delete a published Iris app with backup and recovery.
18
+ */
19
+ export const irisDelete = async () => {
20
+ process.stdout.write('\x1Bc'); // Clear console
21
+
22
+ console.log(chalk.red.bold('\n⚠ Delete Iris App'));
23
+ console.log(chalk.gray('─'.repeat(48)));
24
+ console.log();
25
+
26
+ // Get list of published apps from base.json
27
+ const cachedResults = config.read(null, { filename: "base.json" });
28
+ const cachedIrisApps = Object.values(cachedResults || {})
29
+ .filter(entry => entry.type === 'IrisApp' || entry.Type === 'IrisApp')
30
+ .map(entry => {
31
+ const slug = entry.folderName || (entry.recordId && entry.recordId.startsWith('iris-app:')
32
+ ? entry.recordId.replace('iris-app:', '')
33
+ : null);
34
+ return {
35
+ slug,
36
+ appName: entry.appName || slug,
37
+ folderName: entry.folderName || slug
38
+ };
39
+ })
40
+ .filter(app => app.slug);
41
+
42
+ if (cachedIrisApps.length === 0) {
43
+ console.log(chalk.yellow('No published Iris apps found.'));
44
+ console.log();
45
+ console.log(chalk.gray('Published apps appear here after running:'));
46
+ console.log(chalk.white(` 1. ${chalk.cyan('magentrix vue-run-build')}`));
47
+ console.log(chalk.white(` 2. ${chalk.cyan('magentrix publish')}`));
48
+ console.log();
49
+ return;
50
+ }
51
+
52
+ // Build choices
53
+ const choices = cachedIrisApps.map(app => ({
54
+ name: `${app.appName} (${app.slug})`,
55
+ value: app
56
+ }));
57
+
58
+ choices.push({
59
+ name: 'Cancel',
60
+ value: null
61
+ });
62
+
63
+ // Select app to delete
64
+ const selectedApp = await select({
65
+ message: 'Which Iris app do you want to delete?',
66
+ choices
67
+ });
68
+
69
+ if (!selectedApp) {
70
+ console.log(chalk.gray('Cancelled.'));
71
+ return;
72
+ }
73
+
74
+ const { slug, appName } = selectedApp;
75
+
76
+ // Show destructive warning
77
+ console.log();
78
+ console.log(chalk.bgRed.bold.white(' ⚠ DESTRUCTIVE OPERATION '));
79
+ console.log(chalk.red('─'.repeat(48)));
80
+ console.log(chalk.white('This will permanently delete:'));
81
+ console.log(chalk.red(` • App from server: ${chalk.cyan(appName)} (${slug})`));
82
+ console.log(chalk.red(` • Local files: ${chalk.gray(`src/iris-apps/${slug}/`)}`));
83
+ console.log(chalk.red(` • Navigation menu entry on Magentrix`));
84
+ console.log();
85
+ console.log(chalk.yellow('A recovery backup will be created before deletion.'));
86
+ console.log(chalk.gray('You can restore using: ') + chalk.cyan('magentrix iris-app-recover'));
87
+ console.log(chalk.red('─'.repeat(48)));
88
+ console.log();
89
+
90
+ // Confirm deletion by typing app name
91
+ const confirmation = await input({
92
+ message: `Type the app slug "${slug}" to confirm deletion:`,
93
+ validate: (value) => {
94
+ if (value === slug) return true;
95
+ return `Please type exactly: ${slug}`;
96
+ }
97
+ });
98
+
99
+ if (confirmation !== slug) {
100
+ console.log(chalk.gray('Cancelled.'));
101
+ return;
102
+ }
103
+
104
+ // Acquire delete lock to prevent concurrent deletions
105
+ const lockBasePath = path.join(process.env.HOME || process.env.USERPROFILE || '/tmp', '.magentrix-locks');
106
+ const lockResult = acquireLock(LockTypes.DELETE, {
107
+ context: slug,
108
+ operation: `deleting ${slug}`,
109
+ basePath: lockBasePath
110
+ });
111
+
112
+ // Track if lock was acquired (permission errors are non-fatal for delete)
113
+ let lockAcquired = lockResult.acquired;
114
+ if (!lockResult.acquired) {
115
+ if (lockResult.error?.includes('permission') || lockResult.error?.includes('EACCES')) {
116
+ console.log(chalk.yellow('Warning: Could not create delete lock (permission issue). Proceeding without lock.'));
117
+ lockAcquired = false;
118
+ } else {
119
+ console.log(chalk.red('Cannot delete app:'));
120
+ console.log(chalk.yellow(lockResult.error));
121
+ return;
122
+ }
123
+ }
124
+
125
+ try {
126
+ await performDelete(slug, appName);
127
+ } finally {
128
+ if (lockAcquired) {
129
+ releaseLock(LockTypes.DELETE, { context: slug, basePath: lockBasePath });
130
+ }
131
+ }
132
+ };
133
+
134
+ /**
135
+ * Perform the actual delete operation.
136
+ * @param {string} slug - App slug
137
+ * @param {string} appName - App display name
138
+ */
139
+ async function performDelete(slug, appName) {
140
+ // Check if app is linked
141
+ const linkedProjects = getLinkedProjects();
142
+ const linkedProject = linkedProjects.find(p => p.slug === slug);
143
+
144
+ let shouldUnlink = false;
145
+ if (linkedProject) {
146
+ console.log();
147
+ shouldUnlink = await confirm({
148
+ message: `This app is linked to a Vue project at ${linkedProject.path}. Unlink it?`,
149
+ default: false
150
+ });
151
+ }
152
+
153
+ // Create backup
154
+ console.log();
155
+ console.log(chalk.blue('Creating recovery backup...'));
156
+
157
+ const appPath = path.join(EXPORT_ROOT, IRIS_APPS_DIR, slug);
158
+ const backupResult = await backupIrisApp(appPath, {
159
+ slug,
160
+ appName,
161
+ linkedProject: linkedProject || null
162
+ });
163
+
164
+ if (!backupResult.success) {
165
+ console.log(chalk.red(`Failed to create backup: ${backupResult.error}`));
166
+ console.log(chalk.yellow('Deletion cancelled for safety.'));
167
+ return;
168
+ }
169
+
170
+ console.log(chalk.green(`✓ Backup created: ${backupResult.backupPath}`));
171
+
172
+ // Delete from server
173
+ console.log();
174
+ console.log(chalk.blue('Deleting from Magentrix server...'));
175
+
176
+ const { instanceUrl, token } = await ensureValidCredentials();
177
+ const deleteResult = await deleteIrisAppFromServer(instanceUrl, token.value, slug, {
178
+ updateCache: true // Automatically updates base.json
179
+ });
180
+
181
+ if (!deleteResult.success && deleteResult.error !== 'App not found on server (already deleted)') {
182
+ console.log(chalk.red(`Failed to delete from server: ${deleteResult.error}`));
183
+ console.log(chalk.yellow('Backup preserved. Use ') + chalk.cyan('magentrix iris-app-recover') + chalk.yellow(' to restore.'));
184
+ return;
185
+ }
186
+
187
+ if (deleteResult.error === 'App not found on server (already deleted)') {
188
+ console.log(chalk.yellow('⚠ App not found on server (already deleted)'));
189
+ } else {
190
+ console.log(chalk.green('✓ Deleted from server'));
191
+ }
192
+
193
+ if (deleteResult.cleanedFromCache) {
194
+ console.log(chalk.green('✓ Cache updated'));
195
+ }
196
+
197
+ // Delete local files
198
+ console.log(chalk.blue('Deleting local files...'));
199
+
200
+ const localDeleteResult = deleteLocalIrisAppFiles(appPath);
201
+
202
+ if (localDeleteResult.success) {
203
+ if (localDeleteResult.existed) {
204
+ console.log(chalk.green('✓ Local files deleted'));
205
+ } else {
206
+ console.log(chalk.gray(' (No local files found)'));
207
+ }
208
+ } else if (localDeleteResult.isPermissionError) {
209
+ showPermissionError({
210
+ operation: 'delete',
211
+ targetPath: appPath
212
+ });
213
+ console.log();
214
+ console.log(chalk.gray('Note: The app was deleted from the server and cache.'));
215
+ console.log(chalk.gray('Only local file cleanup failed.'));
216
+ console.log();
217
+ } else if (localDeleteResult.isFileLocked) {
218
+ console.log(chalk.yellow('⚠ Could not delete local files - files are in use'));
219
+ console.log(chalk.gray(localDeleteResult.error));
220
+ console.log();
221
+ console.log(chalk.gray('Note: The app was deleted from the server and cache.'));
222
+ console.log(chalk.gray('Close any programs using these files and delete manually.'));
223
+ console.log();
224
+ } else {
225
+ console.log(chalk.yellow(`⚠ Failed to delete local files: ${localDeleteResult.error}`));
226
+ console.log(chalk.gray(`Path: ${appPath}`));
227
+ console.log(chalk.white('You may need to delete manually.'));
228
+ }
229
+
230
+ // Unlink Vue project if requested
231
+ if (shouldUnlink && linkedProject) {
232
+ console.log(chalk.blue('Unlinking Vue project...'));
233
+ unlinkVueProject(linkedProject.path);
234
+ console.log(chalk.green('✓ Vue project unlinked'));
235
+ }
236
+
237
+ // Summary
238
+ console.log();
239
+ console.log(chalk.green('─'.repeat(48)));
240
+ if (localDeleteResult.success) {
241
+ console.log(chalk.green.bold('✓ Iris App Deleted Successfully!'));
242
+ } else {
243
+ console.log(chalk.yellow.bold('⚠ Iris App Partially Deleted'));
244
+ console.log();
245
+ console.log(chalk.green('✓ Deleted from server'));
246
+ console.log(chalk.green('✓ Cache updated'));
247
+ console.log(chalk.yellow('⚠ Local files require manual deletion'));
248
+ }
249
+ console.log();
250
+ console.log(chalk.cyan('Recovery:'));
251
+ console.log(chalk.white(` Backup saved to: ${chalk.gray(backupResult.backupPath)}`));
252
+ console.log(chalk.white(` To restore, run: ${chalk.cyan('magentrix iris-app-recover')}`));
253
+ console.log();
254
+ }
255
+
256
+ export default irisDelete;