@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,293 +1,293 @@
1
- import chokidar from 'chokidar';
2
- import { ensureValidCredentials } from '../utils/cli/helpers/ensureCredentials.js';
3
- import { withSpinner } from '../utils/spinner.js';
4
- import { ENTITY_FIELD_MAP, ENTITY_TYPE_MAP, TYPE_DIR_MAP } from '../vars/global.js';
5
- import fs from 'fs';
6
- import Config from '../utils/config.js';
7
- import { updateEntity } from '../utils/magentrix/api/updateEntity.js';
8
- import chalk from 'chalk';
9
- import { deleteEntity } from '../utils/magentrix/api/deleteEntity.js';
10
- import { decompressString } from '../utils/compress.js';
11
-
12
- const config = new Config();
13
-
14
- let credentials = {};
15
- let isUpdating = null;
16
- let alreadyWarned = false;
17
-
18
- /**
19
- * Handler for file creation events.
20
- * Triggered when a new file is added to the watched directory.
21
- *
22
- * @async
23
- * @function onAdd
24
- * @param {string} path - The path of the newly added file.
25
- */
26
- const onAdd = async (path) => {
27
- // TODO: Ensure it doesn't try and create a file that has already been created using CLI
28
- // TODO: Handle file addition logic (e.g., queue for remote sync)
29
- // console.log(`[+] File created: ${path}`);
30
-
31
- const pathParts = path.split("\\");
32
- const acceptedTypes = Object.keys(TYPE_DIR_MAP).map(key => TYPE_DIR_MAP[key].directory);
33
- const fileName = pathParts[pathParts.length - 1];
34
- const name = fileName.split(".")[0];
35
-
36
- const fileContent = fs.readFileSync(path, 'utf-8');
37
-
38
- let pathType = null;
39
-
40
- for (const part of pathParts) {
41
- if (acceptedTypes.includes(part)) {
42
- pathType = part;
43
- }
44
- }
45
-
46
- let formattedData;
47
-
48
- if (['Classes', 'Trigger', 'Controllers'].includes(pathType)) {
49
- formattedData = {
50
- Name: name,
51
- Body: fileContent,
52
- Description: "",
53
- Type: ({
54
- "Classes": "Class",
55
- "Triggers": "Trigger",
56
- "Controllers": "Controller"
57
- })[pathType]
58
- };
59
- } else if (['Templates', 'Pages'].includes(pathType)) {
60
- formattedData = {
61
- Name: name,
62
- Content: fileContent,
63
- Description: "",
64
- Type: "Active Page"
65
- };
66
- }
67
-
68
- console.log(formattedData)
69
- // Uncomment to perform creation via API:
70
- // const creationResponse = await withSpinner('Creating file...', async () => {
71
- // return await createEntity(credentials.instanceUrl, credentials.token.value, entityType, formattedData);
72
- // });
73
- };
74
-
75
- /**
76
- * Handler for file modification events.
77
- * Triggered when an existing file is changed.
78
- *
79
- * @async
80
- * @function onChange
81
- * @param {string} path - The path of the modified file.
82
- */
83
- const onChange = async (path) => {
84
- if (isUpdating) {
85
- if (!alreadyWarned) {
86
- process.stdout.write(chalk.yellow('\r⚠ File is currently compiling. Please wait...\n'));
87
- alreadyWarned = true;
88
- }
89
- return;
90
- }
91
-
92
- alreadyWarned = false;
93
-
94
- const fileDataQuery = config.searchObject({ filePath: path }, { global: false, filename: 'base.json' });
95
- const fileData = fileDataQuery?.[0];
96
- if (!fileData) {
97
- // No file found in the base index, no action needed here
98
- return;
99
- }
100
-
101
- process.stdout.write('\x1Bc'); // Clear the console
102
- console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
103
- console.log();
104
-
105
- const recordId = fileData.value.recordId;
106
- const fileType = fileData.value.type;
107
- const fileContents = fs.readFileSync(path, 'utf-8');
108
-
109
- const updateField = ENTITY_FIELD_MAP[fileType];
110
- const entityName = ENTITY_TYPE_MAP[fileType];
111
-
112
- const updateBody = {
113
- Id: recordId,
114
- [updateField]: fileContents
115
- }
116
-
117
- isUpdating = true;
118
- const response = await withSpinner(chalk.gray(`Compiling ${path}...`), async () => {
119
- return await updateEntity(
120
- credentials.instanceUrl,
121
- credentials.token.value,
122
- entityName,
123
- recordId,
124
- updateBody
125
- ).catch(err => {
126
- return { ...err, hasErrors: true }
127
- });
128
- });
129
- isUpdating = false;
130
-
131
- if (response?.hasErrors) {
132
- const err = response;
133
-
134
- // Clear line and provide an error heading
135
- console.log();
136
- console.log(chalk.bgRed.bold.white(' ✖ Magentrix API Error '));
137
- console.log(chalk.redBright('─'.repeat(48)));
138
-
139
- if (err.response && Array.isArray(err.response.errors)) {
140
- const errors = err.response.errors;
141
- console.log(
142
- chalk.red.bold(
143
- `Found ${errors.length} error${errors.length !== 1 ? 's' : ''}:`
144
- )
145
- );
146
- errors.forEach((error, idx) => {
147
- // Show error status (if available), code, and message, all prettified
148
- const code = error.code ? chalk.gray(`[${error.code}] `) : '';
149
- const status = error.status ? chalk.yellow(`[${error.status}] `) : '';
150
- const msg = chalk.whiteBright(error.message);
151
- console.log(
152
- `${chalk.redBright(' •')} ${status}${code}${msg}`
153
- );
154
- });
155
- } else if (err.response && err.response.message) {
156
- // Single message fallback
157
- console.log(chalk.red(' • ') + chalk.whiteBright(err.response.message));
158
- } else if (err.message) {
159
- // Any unexpected error
160
- console.log(chalk.red(' • ') + chalk.whiteBright(err.message));
161
- } else {
162
- console.log(chalk.red(' • ') + chalk.whiteBright('An unexpected error has occurred.'));
163
- }
164
-
165
- console.log(chalk.redBright('─'.repeat(48)));
166
- } else {
167
- // Clean, celebratory message!
168
- console.log();
169
- console.log(
170
- chalk.bgGreen.bold.white(' ✔ File Compiled & Saved! ')
171
- );
172
- console.log(chalk.greenBright('─'.repeat(48)));
173
- console.log(
174
- chalk.greenBright.bold('Your file was compiled and saved on the remote Magentrix server.')
175
- );
176
- // Optionally: include file info or extra details if available
177
- if (response.fileName) {
178
- console.log(chalk.whiteBright(`File: ${chalk.cyan(response.fileName)}`));
179
- }
180
- if (response.lastModified) {
181
- console.log(
182
- chalk.gray(`Last Modified: ${new Date(response.lastModified).toLocaleString()}`)
183
- );
184
- }
185
- if (response.recordId) {
186
- console.log(chalk.gray(`Record ID: ${chalk.yellow(response.recordId)}`));
187
- }
188
- // Add spacing and line
189
- console.log(chalk.greenBright('─'.repeat(48)));
190
- console.log();
191
- }
192
- };
193
-
194
- /**
195
- * Handler for file deletion events.
196
- * Triggered when a file is removed from the watched directory.
197
- *
198
- * @async
199
- * @function onUnlink
200
- * @param {string} path - The path of the deleted file.
201
- */
202
- const onUnlink = async (path) => {
203
- process.stdout.write('\x1Bc'); // Clear the console
204
- console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
205
- console.log();
206
-
207
- const fileDataQuery = config.searchObject({ filePath: path }, { global: false, filename: 'base.json' });
208
- const fileData = fileDataQuery?.[0];
209
- if (!fileData) {
210
- console.log(chalk.gray(`⚠️ File removed, but not found in index: ${path}`));
211
- return;
212
- }
213
-
214
- const recordId = fileData.value.recordId;
215
- const fileType = fileData.value.type;
216
- const entityName = ENTITY_TYPE_MAP[fileType];
217
-
218
- const response = await withSpinner(`🗑️ Deleting remote ${entityName} for: ${path}`, async () => {
219
- return await deleteEntity(
220
- credentials.instanceUrl,
221
- credentials.token.value,
222
- entityName,
223
- recordId
224
- ).catch(err => {
225
- return { ...err?.response, hasErrors: true };
226
- });
227
- });
228
-
229
- if (response?.hasErrors) {
230
- try {
231
- // Put the file back with the last synced content
232
- const lastContent = decompressString(fileData.value.compressedContent);
233
- fs.writeFileSync(path, lastContent);
234
- } catch (err) {
235
- console.warn(`⚠️ Failed to restore deleted file at "${path}". Reason: ${err.message}`);
236
- }
237
- }
238
-
239
- if (response?.success) {
240
- console.log(chalk.green.bold(`✔ Successfully deleted remote ${entityName} for:`), chalk.whiteBright(path));
241
- } else if (response?.hasErrors || response?.errors?.length > 0) {
242
- console.log();
243
- console.log(chalk.bgRed.bold.white(' ✖ Deletion Failed '));
244
- console.log(chalk.redBright('─'.repeat(48)));
245
- const errors = response.errors || [];
246
- if (errors.length > 0) {
247
- errors.forEach((err, i) => {
248
- const code = err.code ? chalk.gray(`[${err.code}] `) : '';
249
- const status = err.status ? chalk.yellow(`[${err.status}] `) : '';
250
- const msg = chalk.whiteBright(err.message);
251
- console.log(`${chalk.redBright(' •')} ${status}${code}${msg}`);
252
- });
253
- } else {
254
- console.log(chalk.red('An unknown error occurred during deletion.'));
255
- }
256
- } else {
257
- console.log(chalk.yellow(`⚠️ Unexpected response while deleting: ${path}`));
258
- }
259
- };
260
-
261
- const startWatcher = () => {
262
- console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
263
- console.log();
264
-
265
- const watcher = chokidar.watch('.', {
266
- ignored: /(^|[\/\\])\../, // Ignore dotfiles and .git etc.
267
- persistent: true,
268
- ignoreInitial: true // Don't fire events for files already present
269
- });
270
-
271
- watcher
272
- .on('add', onAdd)
273
- .on('change', onChange)
274
- .on('unlink', onUnlink);
275
- }
276
-
277
- /**
278
- * Initializes and starts the file watcher for Magentrix CLI.
279
- * Watches the current directory for file changes (add, change, unlink)
280
- * and triggers remote sync as needed.
281
- *
282
- * @function watch
283
- * @returns {void}
284
- */
285
- export const autoPublish = async () => {
286
- process.stdout.write('\x1Bc'); // Clear the console
287
-
288
- credentials = await withSpinner('Authenticating...', async () => {
289
- return await ensureValidCredentials();
290
- });
291
-
292
- startWatcher();
293
- };
1
+ import chokidar from 'chokidar';
2
+ import { ensureValidCredentials } from '../utils/cli/helpers/ensureCredentials.js';
3
+ import { withSpinner } from '../utils/spinner.js';
4
+ import { ENTITY_FIELD_MAP, ENTITY_TYPE_MAP, TYPE_DIR_MAP } from '../vars/global.js';
5
+ import fs from 'fs';
6
+ import Config from '../utils/config.js';
7
+ import { updateEntity } from '../utils/magentrix/api/updateEntity.js';
8
+ import chalk from 'chalk';
9
+ import { deleteEntity } from '../utils/magentrix/api/deleteEntity.js';
10
+ import { decompressString } from '../utils/compress.js';
11
+
12
+ const config = new Config();
13
+
14
+ let credentials = {};
15
+ let isUpdating = null;
16
+ let alreadyWarned = false;
17
+
18
+ /**
19
+ * Handler for file creation events.
20
+ * Triggered when a new file is added to the watched directory.
21
+ *
22
+ * @async
23
+ * @function onAdd
24
+ * @param {string} path - The path of the newly added file.
25
+ */
26
+ const onAdd = async (path) => {
27
+ // TODO: Ensure it doesn't try and create a file that has already been created using CLI
28
+ // TODO: Handle file addition logic (e.g., queue for remote sync)
29
+ // console.log(`[+] File created: ${path}`);
30
+
31
+ const pathParts = path.split("\\");
32
+ const acceptedTypes = Object.keys(TYPE_DIR_MAP).map(key => TYPE_DIR_MAP[key].directory);
33
+ const fileName = pathParts[pathParts.length - 1];
34
+ const name = fileName.split(".")[0];
35
+
36
+ const fileContent = fs.readFileSync(path, 'utf-8');
37
+
38
+ let pathType = null;
39
+
40
+ for (const part of pathParts) {
41
+ if (acceptedTypes.includes(part)) {
42
+ pathType = part;
43
+ }
44
+ }
45
+
46
+ let formattedData;
47
+
48
+ if (['Classes', 'Trigger', 'Controllers'].includes(pathType)) {
49
+ formattedData = {
50
+ Name: name,
51
+ Body: fileContent,
52
+ Description: "",
53
+ Type: ({
54
+ "Classes": "Class",
55
+ "Triggers": "Trigger",
56
+ "Controllers": "Controller"
57
+ })[pathType]
58
+ };
59
+ } else if (['Templates', 'Pages'].includes(pathType)) {
60
+ formattedData = {
61
+ Name: name,
62
+ Content: fileContent,
63
+ Description: "",
64
+ Type: "Active Page"
65
+ };
66
+ }
67
+
68
+ console.log(formattedData)
69
+ // Uncomment to perform creation via API:
70
+ // const creationResponse = await withSpinner('Creating file...', async () => {
71
+ // return await createEntity(credentials.instanceUrl, credentials.token.value, entityType, formattedData);
72
+ // });
73
+ };
74
+
75
+ /**
76
+ * Handler for file modification events.
77
+ * Triggered when an existing file is changed.
78
+ *
79
+ * @async
80
+ * @function onChange
81
+ * @param {string} path - The path of the modified file.
82
+ */
83
+ const onChange = async (path) => {
84
+ if (isUpdating) {
85
+ if (!alreadyWarned) {
86
+ process.stdout.write(chalk.yellow('\r⚠ File is currently compiling. Please wait...\n'));
87
+ alreadyWarned = true;
88
+ }
89
+ return;
90
+ }
91
+
92
+ alreadyWarned = false;
93
+
94
+ const fileDataQuery = config.searchObject({ filePath: path }, { global: false, filename: 'base.json' });
95
+ const fileData = fileDataQuery?.[0];
96
+ if (!fileData) {
97
+ // No file found in the base index, no action needed here
98
+ return;
99
+ }
100
+
101
+ process.stdout.write('\x1Bc'); // Clear the console
102
+ console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
103
+ console.log();
104
+
105
+ const recordId = fileData.value.recordId;
106
+ const fileType = fileData.value.type;
107
+ const fileContents = fs.readFileSync(path, 'utf-8');
108
+
109
+ const updateField = ENTITY_FIELD_MAP[fileType];
110
+ const entityName = ENTITY_TYPE_MAP[fileType];
111
+
112
+ const updateBody = {
113
+ Id: recordId,
114
+ [updateField]: fileContents
115
+ }
116
+
117
+ isUpdating = true;
118
+ const response = await withSpinner(chalk.gray(`Compiling ${path}...`), async () => {
119
+ return await updateEntity(
120
+ credentials.instanceUrl,
121
+ credentials.token.value,
122
+ entityName,
123
+ recordId,
124
+ updateBody
125
+ ).catch(err => {
126
+ return { ...err, hasErrors: true }
127
+ });
128
+ });
129
+ isUpdating = false;
130
+
131
+ if (response?.hasErrors) {
132
+ const err = response;
133
+
134
+ // Clear line and provide an error heading
135
+ console.log();
136
+ console.log(chalk.bgRed.bold.white(' ✖ Magentrix API Error '));
137
+ console.log(chalk.redBright('─'.repeat(48)));
138
+
139
+ if (err.response && Array.isArray(err.response.errors)) {
140
+ const errors = err.response.errors;
141
+ console.log(
142
+ chalk.red.bold(
143
+ `Found ${errors.length} error${errors.length !== 1 ? 's' : ''}:`
144
+ )
145
+ );
146
+ errors.forEach((error, idx) => {
147
+ // Show error status (if available), code, and message, all prettified
148
+ const code = error.code ? chalk.gray(`[${error.code}] `) : '';
149
+ const status = error.status ? chalk.yellow(`[${error.status}] `) : '';
150
+ const msg = chalk.whiteBright(error.message);
151
+ console.log(
152
+ `${chalk.redBright(' •')} ${status}${code}${msg}`
153
+ );
154
+ });
155
+ } else if (err.response && err.response.message) {
156
+ // Single message fallback
157
+ console.log(chalk.red(' • ') + chalk.whiteBright(err.response.message));
158
+ } else if (err.message) {
159
+ // Any unexpected error
160
+ console.log(chalk.red(' • ') + chalk.whiteBright(err.message));
161
+ } else {
162
+ console.log(chalk.red(' • ') + chalk.whiteBright('An unexpected error has occurred.'));
163
+ }
164
+
165
+ console.log(chalk.redBright('─'.repeat(48)));
166
+ } else {
167
+ // Clean, celebratory message!
168
+ console.log();
169
+ console.log(
170
+ chalk.bgGreen.bold.white(' ✔ File Compiled & Saved! ')
171
+ );
172
+ console.log(chalk.greenBright('─'.repeat(48)));
173
+ console.log(
174
+ chalk.greenBright.bold('Your file was compiled and saved on the remote Magentrix server.')
175
+ );
176
+ // Optionally: include file info or extra details if available
177
+ if (response.fileName) {
178
+ console.log(chalk.whiteBright(`File: ${chalk.cyan(response.fileName)}`));
179
+ }
180
+ if (response.lastModified) {
181
+ console.log(
182
+ chalk.gray(`Last Modified: ${new Date(response.lastModified).toLocaleString()}`)
183
+ );
184
+ }
185
+ if (response.recordId) {
186
+ console.log(chalk.gray(`Record ID: ${chalk.yellow(response.recordId)}`));
187
+ }
188
+ // Add spacing and line
189
+ console.log(chalk.greenBright('─'.repeat(48)));
190
+ console.log();
191
+ }
192
+ };
193
+
194
+ /**
195
+ * Handler for file deletion events.
196
+ * Triggered when a file is removed from the watched directory.
197
+ *
198
+ * @async
199
+ * @function onUnlink
200
+ * @param {string} path - The path of the deleted file.
201
+ */
202
+ const onUnlink = async (path) => {
203
+ process.stdout.write('\x1Bc'); // Clear the console
204
+ console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
205
+ console.log();
206
+
207
+ const fileDataQuery = config.searchObject({ filePath: path }, { global: false, filename: 'base.json' });
208
+ const fileData = fileDataQuery?.[0];
209
+ if (!fileData) {
210
+ console.log(chalk.gray(`⚠️ File removed, but not found in index: ${path}`));
211
+ return;
212
+ }
213
+
214
+ const recordId = fileData.value.recordId;
215
+ const fileType = fileData.value.type;
216
+ const entityName = ENTITY_TYPE_MAP[fileType];
217
+
218
+ const response = await withSpinner(`🗑️ Deleting remote ${entityName} for: ${path}`, async () => {
219
+ return await deleteEntity(
220
+ credentials.instanceUrl,
221
+ credentials.token.value,
222
+ entityName,
223
+ recordId
224
+ ).catch(err => {
225
+ return { ...err?.response, hasErrors: true };
226
+ });
227
+ });
228
+
229
+ if (response?.hasErrors) {
230
+ try {
231
+ // Put the file back with the last synced content
232
+ const lastContent = decompressString(fileData.value.compressedContent);
233
+ fs.writeFileSync(path, lastContent);
234
+ } catch (err) {
235
+ console.warn(`⚠️ Failed to restore deleted file at "${path}". Reason: ${err.message}`);
236
+ }
237
+ }
238
+
239
+ if (response?.success) {
240
+ console.log(chalk.green.bold(`✔ Successfully deleted remote ${entityName} for:`), chalk.whiteBright(path));
241
+ } else if (response?.hasErrors || response?.errors?.length > 0) {
242
+ console.log();
243
+ console.log(chalk.bgRed.bold.white(' ✖ Deletion Failed '));
244
+ console.log(chalk.redBright('─'.repeat(48)));
245
+ const errors = response.errors || [];
246
+ if (errors.length > 0) {
247
+ errors.forEach((err, i) => {
248
+ const code = err.code ? chalk.gray(`[${err.code}] `) : '';
249
+ const status = err.status ? chalk.yellow(`[${err.status}] `) : '';
250
+ const msg = chalk.whiteBright(err.message);
251
+ console.log(`${chalk.redBright(' •')} ${status}${code}${msg}`);
252
+ });
253
+ } else {
254
+ console.log(chalk.red('An unknown error occurred during deletion.'));
255
+ }
256
+ } else {
257
+ console.log(chalk.yellow(`⚠️ Unexpected response while deleting: ${path}`));
258
+ }
259
+ };
260
+
261
+ const startWatcher = () => {
262
+ console.log('🔄 Watching for file changes... Any edits will be detected and queued for remote update.');
263
+ console.log();
264
+
265
+ const watcher = chokidar.watch('.', {
266
+ ignored: /(^|[\/\\])\../, // Ignore dotfiles and .git etc.
267
+ persistent: true,
268
+ ignoreInitial: true // Don't fire events for files already present
269
+ });
270
+
271
+ watcher
272
+ .on('add', onAdd)
273
+ .on('change', onChange)
274
+ .on('unlink', onUnlink);
275
+ }
276
+
277
+ /**
278
+ * Initializes and starts the file watcher for Magentrix CLI.
279
+ * Watches the current directory for file changes (add, change, unlink)
280
+ * and triggers remote sync as needed.
281
+ *
282
+ * @function watch
283
+ * @returns {void}
284
+ */
285
+ export const autoPublish = async () => {
286
+ process.stdout.write('\x1Bc'); // Clear the console
287
+
288
+ credentials = await withSpinner('Authenticating...', async () => {
289
+ return await ensureValidCredentials();
290
+ });
291
+
292
+ startWatcher();
293
+ };