@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.
- package/LICENSE +25 -25
- package/README.md +1166 -1166
- package/actions/autopublish.old.js +293 -293
- package/actions/config.js +182 -182
- package/actions/create.js +466 -466
- package/actions/help.js +164 -164
- package/actions/iris/buildStage.js +874 -874
- package/actions/iris/delete.js +256 -256
- package/actions/iris/dev.js +391 -391
- package/actions/iris/index.js +6 -6
- package/actions/iris/link.js +375 -375
- package/actions/iris/recover.js +268 -268
- package/actions/main.js +80 -80
- package/actions/publish.js +1420 -1420
- package/actions/pull.js +684 -684
- package/actions/setup.js +148 -148
- package/actions/status.js +17 -17
- package/actions/update.js +248 -248
- package/bin/magentrix.js +393 -393
- package/package.json +55 -55
- package/utils/assetPaths.js +158 -158
- package/utils/autopublishLock.js +77 -77
- package/utils/cacher.js +206 -206
- package/utils/cli/checkInstanceUrl.js +76 -74
- package/utils/cli/helpers/compare.js +282 -282
- package/utils/cli/helpers/ensureApiKey.js +63 -63
- package/utils/cli/helpers/ensureCredentials.js +68 -68
- package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
- package/utils/cli/writeRecords.js +262 -262
- package/utils/compare.js +135 -135
- package/utils/compress.js +17 -17
- package/utils/config.js +527 -527
- package/utils/debug.js +144 -144
- package/utils/diagnostics/testPublishLogic.js +96 -96
- package/utils/diff.js +49 -49
- package/utils/downloadAssets.js +291 -291
- package/utils/filetag.js +115 -115
- package/utils/hash.js +14 -14
- package/utils/iris/backup.js +411 -411
- package/utils/iris/builder.js +541 -541
- package/utils/iris/config-reader.js +664 -664
- package/utils/iris/deleteHelper.js +150 -150
- package/utils/iris/errors.js +537 -537
- package/utils/iris/linker.js +601 -601
- package/utils/iris/lock.js +360 -360
- package/utils/iris/validation.js +360 -360
- package/utils/iris/validator.js +281 -281
- package/utils/iris/zipper.js +248 -248
- package/utils/logger.js +291 -291
- package/utils/magentrix/api/assets.js +220 -220
- package/utils/magentrix/api/auth.js +107 -107
- package/utils/magentrix/api/createEntity.js +61 -61
- package/utils/magentrix/api/deleteEntity.js +55 -55
- package/utils/magentrix/api/iris.js +251 -251
- package/utils/magentrix/api/meqlQuery.js +36 -36
- package/utils/magentrix/api/retrieveEntity.js +86 -86
- package/utils/magentrix/api/updateEntity.js +66 -66
- package/utils/magentrix/fetch.js +168 -168
- package/utils/merge.js +22 -22
- package/utils/permissionError.js +70 -70
- package/utils/preferences.js +40 -40
- package/utils/progress.js +469 -469
- package/utils/spinner.js +43 -43
- package/utils/template.js +52 -52
- package/utils/updateFileBase.js +121 -121
- package/utils/workspaces.js +108 -108
- package/vars/config.js +11 -11
- package/vars/global.js +50 -50
package/utils/logger.js
CHANGED
|
@@ -1,291 +1,291 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import Config from './config.js';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
6
|
-
|
|
7
|
-
const config = new Config();
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Logger utility for tracking errors, warnings, and operations during pull/publish.
|
|
11
|
-
* Logs are stored in .magentrix/logs/ directory.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export class Logger {
|
|
15
|
-
constructor(operationName = 'operation') {
|
|
16
|
-
this.operationName = operationName;
|
|
17
|
-
this.logDir = '.magentrix/logs';
|
|
18
|
-
this.timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
|
|
19
|
-
this.logFile = path.join(this.logDir, `${operationName}-${this.timestamp}.log`);
|
|
20
|
-
this.errors = [];
|
|
21
|
-
this.warnings = [];
|
|
22
|
-
this.infos = [];
|
|
23
|
-
this.loggingEnabled = null; // Will be determined on first write
|
|
24
|
-
|
|
25
|
-
// Check if logging is enabled in config
|
|
26
|
-
this.checkLoggingPreference();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Check user's logging preference from config
|
|
31
|
-
*/
|
|
32
|
-
checkLoggingPreference() {
|
|
33
|
-
const preference = config.read('saveLogs', { global: true });
|
|
34
|
-
|
|
35
|
-
if (preference !== undefined && preference !== null) {
|
|
36
|
-
this.loggingEnabled = preference === true || preference === 'true';
|
|
37
|
-
}
|
|
38
|
-
// If undefined, we'll prompt on first write
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Prompt user about logging preference (only once)
|
|
43
|
-
*/
|
|
44
|
-
async promptLoggingPreference() {
|
|
45
|
-
console.log('');
|
|
46
|
-
console.log(chalk.cyan('📋 Log File Settings'));
|
|
47
|
-
console.log(chalk.gray('Magentrix CLI can save detailed operation logs for debugging.'));
|
|
48
|
-
console.log('');
|
|
49
|
-
|
|
50
|
-
const answer = await inquirer.prompt([
|
|
51
|
-
{
|
|
52
|
-
type: 'confirm',
|
|
53
|
-
name: 'saveLogs',
|
|
54
|
-
message: 'Would you like to save operation logs to files?',
|
|
55
|
-
default: true
|
|
56
|
-
}
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
|
-
this.loggingEnabled = answer.saveLogs;
|
|
60
|
-
config.save('saveLogs', answer.saveLogs, { global: true });
|
|
61
|
-
|
|
62
|
-
if (answer.saveLogs) {
|
|
63
|
-
console.log(chalk.green('✓ Logs will be saved to .magentrix/logs/'));
|
|
64
|
-
} else {
|
|
65
|
-
console.log(chalk.gray('Logs disabled. You can enable them anytime with: magentrix config set logs true'));
|
|
66
|
-
}
|
|
67
|
-
console.log('');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Initialize log file if logging is enabled
|
|
72
|
-
*/
|
|
73
|
-
async initLogFile() {
|
|
74
|
-
if (this.loggingEnabled === null) {
|
|
75
|
-
// First time - prompt user
|
|
76
|
-
await this.promptLoggingPreference();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (this.loggingEnabled) {
|
|
80
|
-
// Ensure log directory exists
|
|
81
|
-
if (!fs.existsSync(this.logDir)) {
|
|
82
|
-
fs.mkdirSync(this.logDir, { recursive: true });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Initialize log file
|
|
86
|
-
this.writeToFile(`=== ${this.operationName.toUpperCase()} LOG ===`);
|
|
87
|
-
this.writeToFile(`Started: ${new Date().toISOString()}`);
|
|
88
|
-
this.writeToFile(`Working Directory: ${process.cwd()}`);
|
|
89
|
-
this.writeToFile('');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Write a line to the log file (internal method)
|
|
95
|
-
*/
|
|
96
|
-
writeToFile(message) {
|
|
97
|
-
if (this.loggingEnabled) {
|
|
98
|
-
fs.appendFileSync(this.logFile, message + '\n');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Log an info message
|
|
104
|
-
*/
|
|
105
|
-
info(message, details = null) {
|
|
106
|
-
const timestamp = new Date().toISOString();
|
|
107
|
-
const entry = { timestamp, level: 'INFO', message, details };
|
|
108
|
-
this.infos.push(entry);
|
|
109
|
-
|
|
110
|
-
this.writeToFile(`[${timestamp}] INFO: ${message}`);
|
|
111
|
-
if (details) {
|
|
112
|
-
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Log a warning message
|
|
118
|
-
*/
|
|
119
|
-
warning(message, details = null) {
|
|
120
|
-
const timestamp = new Date().toISOString();
|
|
121
|
-
const entry = { timestamp, level: 'WARNING', message, details };
|
|
122
|
-
this.warnings.push(entry);
|
|
123
|
-
|
|
124
|
-
this.writeToFile(`[${timestamp}] WARNING: ${message}`);
|
|
125
|
-
if (details) {
|
|
126
|
-
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Log an error message
|
|
132
|
-
* @param {string} message - Error message
|
|
133
|
-
* @param {Error|null} error - Error object
|
|
134
|
-
* @param {object|null} details - Additional details
|
|
135
|
-
* @param {string|null} hint - Helpful hint for resolving the error
|
|
136
|
-
*/
|
|
137
|
-
error(message, error = null, details = null, hint = null) {
|
|
138
|
-
const timestamp = new Date().toISOString();
|
|
139
|
-
const entry = {
|
|
140
|
-
timestamp,
|
|
141
|
-
level: 'ERROR',
|
|
142
|
-
message,
|
|
143
|
-
error: error ? error.toString() : null,
|
|
144
|
-
stack: error?.stack || null,
|
|
145
|
-
details,
|
|
146
|
-
hint
|
|
147
|
-
};
|
|
148
|
-
this.errors.push(entry);
|
|
149
|
-
|
|
150
|
-
this.writeToFile(`[${timestamp}] ERROR: ${message}`);
|
|
151
|
-
if (error) {
|
|
152
|
-
this.writeToFile(` Error: ${error.toString()}`);
|
|
153
|
-
if (error.stack) {
|
|
154
|
-
this.writeToFile(` Stack: ${error.stack}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (details) {
|
|
158
|
-
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get a summary of the log
|
|
164
|
-
*/
|
|
165
|
-
getSummary() {
|
|
166
|
-
return {
|
|
167
|
-
errors: this.errors.length,
|
|
168
|
-
warnings: this.warnings.length,
|
|
169
|
-
infos: this.infos.length,
|
|
170
|
-
logFile: this.logFile
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get the most recent errors (for preview)
|
|
176
|
-
*/
|
|
177
|
-
getRecentErrors(count = 3) {
|
|
178
|
-
return this.errors.slice(-count);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Get the most recent warnings (for preview)
|
|
183
|
-
*/
|
|
184
|
-
getRecentWarnings(count = 3) {
|
|
185
|
-
return this.warnings.slice(-count);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Display a summary to the console
|
|
190
|
-
*/
|
|
191
|
-
displaySummary() {
|
|
192
|
-
const summary = this.getSummary();
|
|
193
|
-
|
|
194
|
-
if (summary.errors > 0 || summary.warnings > 0) {
|
|
195
|
-
console.log('');
|
|
196
|
-
console.log(chalk.bold('Issues Summary:'));
|
|
197
|
-
|
|
198
|
-
if (summary.errors > 0) {
|
|
199
|
-
console.log(chalk.red(` ✗ ${summary.errors} error(s)`));
|
|
200
|
-
|
|
201
|
-
// Show preview of recent errors
|
|
202
|
-
const recentErrors = this.getRecentErrors(3);
|
|
203
|
-
recentErrors.forEach((err, idx) => {
|
|
204
|
-
console.log(chalk.red(` ${idx + 1}. ${err.message}`));
|
|
205
|
-
if (err.hint) {
|
|
206
|
-
console.log(chalk.yellow(` ${err.hint}`));
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
if (summary.errors > 3) {
|
|
211
|
-
console.log(chalk.gray(` ... and ${summary.errors - 3} more`));
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (summary.warnings > 0) {
|
|
216
|
-
console.log(chalk.yellow(` ⚠ ${summary.warnings} warning(s)`));
|
|
217
|
-
|
|
218
|
-
// Show preview of recent warnings
|
|
219
|
-
const recentWarnings = this.getRecentWarnings(2);
|
|
220
|
-
recentWarnings.forEach((warn, idx) => {
|
|
221
|
-
console.log(chalk.yellow(` ${idx + 1}. ${warn.message}`));
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
if (summary.warnings > 2) {
|
|
225
|
-
console.log(chalk.gray(` ... and ${summary.warnings - 2} more`));
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Only show log file path if logging is enabled
|
|
230
|
-
if (this.loggingEnabled) {
|
|
231
|
-
console.log('');
|
|
232
|
-
console.log(chalk.cyan(`📄 Full log: ${chalk.white(summary.logFile)}`));
|
|
233
|
-
console.log(chalk.gray(` View with: cat ${summary.logFile}`));
|
|
234
|
-
}
|
|
235
|
-
console.log('');
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Finalize the log file
|
|
241
|
-
*/
|
|
242
|
-
close() {
|
|
243
|
-
this.writeToFile('');
|
|
244
|
-
this.writeToFile(`Completed: ${new Date().toISOString()}`);
|
|
245
|
-
this.writeToFile(`Summary: ${this.errors.length} errors, ${this.warnings.length} warnings, ${this.infos.length} info messages`);
|
|
246
|
-
this.writeToFile('=== END LOG ===');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Clean up old log files (keep only last N logs)
|
|
251
|
-
*/
|
|
252
|
-
static cleanupOldLogs(keepCount = 10) {
|
|
253
|
-
const logDir = '.magentrix/logs';
|
|
254
|
-
|
|
255
|
-
if (!fs.existsSync(logDir)) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const files = fs.readdirSync(logDir)
|
|
261
|
-
.filter(f => f.endsWith('.log'))
|
|
262
|
-
.map(f => ({
|
|
263
|
-
name: f,
|
|
264
|
-
path: path.join(logDir, f),
|
|
265
|
-
time: fs.statSync(path.join(logDir, f)).mtime.getTime()
|
|
266
|
-
}))
|
|
267
|
-
.sort((a, b) => b.time - a.time); // Sort by newest first
|
|
268
|
-
|
|
269
|
-
// Delete files beyond keepCount
|
|
270
|
-
if (files.length > keepCount) {
|
|
271
|
-
const toDelete = files.slice(keepCount);
|
|
272
|
-
toDelete.forEach(file => {
|
|
273
|
-
try {
|
|
274
|
-
fs.unlinkSync(file.path);
|
|
275
|
-
} catch (err) {
|
|
276
|
-
// Ignore errors when deleting old logs
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
} catch (err) {
|
|
281
|
-
// Ignore errors in cleanup
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Create a logger instance for an operation
|
|
288
|
-
*/
|
|
289
|
-
export function createLogger(operationName) {
|
|
290
|
-
return new Logger(operationName);
|
|
291
|
-
}
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import Config from './config.js';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
|
|
7
|
+
const config = new Config();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Logger utility for tracking errors, warnings, and operations during pull/publish.
|
|
11
|
+
* Logs are stored in .magentrix/logs/ directory.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export class Logger {
|
|
15
|
+
constructor(operationName = 'operation') {
|
|
16
|
+
this.operationName = operationName;
|
|
17
|
+
this.logDir = '.magentrix/logs';
|
|
18
|
+
this.timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
|
|
19
|
+
this.logFile = path.join(this.logDir, `${operationName}-${this.timestamp}.log`);
|
|
20
|
+
this.errors = [];
|
|
21
|
+
this.warnings = [];
|
|
22
|
+
this.infos = [];
|
|
23
|
+
this.loggingEnabled = null; // Will be determined on first write
|
|
24
|
+
|
|
25
|
+
// Check if logging is enabled in config
|
|
26
|
+
this.checkLoggingPreference();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check user's logging preference from config
|
|
31
|
+
*/
|
|
32
|
+
checkLoggingPreference() {
|
|
33
|
+
const preference = config.read('saveLogs', { global: true });
|
|
34
|
+
|
|
35
|
+
if (preference !== undefined && preference !== null) {
|
|
36
|
+
this.loggingEnabled = preference === true || preference === 'true';
|
|
37
|
+
}
|
|
38
|
+
// If undefined, we'll prompt on first write
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Prompt user about logging preference (only once)
|
|
43
|
+
*/
|
|
44
|
+
async promptLoggingPreference() {
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log(chalk.cyan('📋 Log File Settings'));
|
|
47
|
+
console.log(chalk.gray('Magentrix CLI can save detailed operation logs for debugging.'));
|
|
48
|
+
console.log('');
|
|
49
|
+
|
|
50
|
+
const answer = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'confirm',
|
|
53
|
+
name: 'saveLogs',
|
|
54
|
+
message: 'Would you like to save operation logs to files?',
|
|
55
|
+
default: true
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
this.loggingEnabled = answer.saveLogs;
|
|
60
|
+
config.save('saveLogs', answer.saveLogs, { global: true });
|
|
61
|
+
|
|
62
|
+
if (answer.saveLogs) {
|
|
63
|
+
console.log(chalk.green('✓ Logs will be saved to .magentrix/logs/'));
|
|
64
|
+
} else {
|
|
65
|
+
console.log(chalk.gray('Logs disabled. You can enable them anytime with: magentrix config set logs true'));
|
|
66
|
+
}
|
|
67
|
+
console.log('');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Initialize log file if logging is enabled
|
|
72
|
+
*/
|
|
73
|
+
async initLogFile() {
|
|
74
|
+
if (this.loggingEnabled === null) {
|
|
75
|
+
// First time - prompt user
|
|
76
|
+
await this.promptLoggingPreference();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (this.loggingEnabled) {
|
|
80
|
+
// Ensure log directory exists
|
|
81
|
+
if (!fs.existsSync(this.logDir)) {
|
|
82
|
+
fs.mkdirSync(this.logDir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Initialize log file
|
|
86
|
+
this.writeToFile(`=== ${this.operationName.toUpperCase()} LOG ===`);
|
|
87
|
+
this.writeToFile(`Started: ${new Date().toISOString()}`);
|
|
88
|
+
this.writeToFile(`Working Directory: ${process.cwd()}`);
|
|
89
|
+
this.writeToFile('');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Write a line to the log file (internal method)
|
|
95
|
+
*/
|
|
96
|
+
writeToFile(message) {
|
|
97
|
+
if (this.loggingEnabled) {
|
|
98
|
+
fs.appendFileSync(this.logFile, message + '\n');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Log an info message
|
|
104
|
+
*/
|
|
105
|
+
info(message, details = null) {
|
|
106
|
+
const timestamp = new Date().toISOString();
|
|
107
|
+
const entry = { timestamp, level: 'INFO', message, details };
|
|
108
|
+
this.infos.push(entry);
|
|
109
|
+
|
|
110
|
+
this.writeToFile(`[${timestamp}] INFO: ${message}`);
|
|
111
|
+
if (details) {
|
|
112
|
+
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Log a warning message
|
|
118
|
+
*/
|
|
119
|
+
warning(message, details = null) {
|
|
120
|
+
const timestamp = new Date().toISOString();
|
|
121
|
+
const entry = { timestamp, level: 'WARNING', message, details };
|
|
122
|
+
this.warnings.push(entry);
|
|
123
|
+
|
|
124
|
+
this.writeToFile(`[${timestamp}] WARNING: ${message}`);
|
|
125
|
+
if (details) {
|
|
126
|
+
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Log an error message
|
|
132
|
+
* @param {string} message - Error message
|
|
133
|
+
* @param {Error|null} error - Error object
|
|
134
|
+
* @param {object|null} details - Additional details
|
|
135
|
+
* @param {string|null} hint - Helpful hint for resolving the error
|
|
136
|
+
*/
|
|
137
|
+
error(message, error = null, details = null, hint = null) {
|
|
138
|
+
const timestamp = new Date().toISOString();
|
|
139
|
+
const entry = {
|
|
140
|
+
timestamp,
|
|
141
|
+
level: 'ERROR',
|
|
142
|
+
message,
|
|
143
|
+
error: error ? error.toString() : null,
|
|
144
|
+
stack: error?.stack || null,
|
|
145
|
+
details,
|
|
146
|
+
hint
|
|
147
|
+
};
|
|
148
|
+
this.errors.push(entry);
|
|
149
|
+
|
|
150
|
+
this.writeToFile(`[${timestamp}] ERROR: ${message}`);
|
|
151
|
+
if (error) {
|
|
152
|
+
this.writeToFile(` Error: ${error.toString()}`);
|
|
153
|
+
if (error.stack) {
|
|
154
|
+
this.writeToFile(` Stack: ${error.stack}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (details) {
|
|
158
|
+
this.writeToFile(` Details: ${typeof details === 'object' ? JSON.stringify(details, null, 2) : details}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get a summary of the log
|
|
164
|
+
*/
|
|
165
|
+
getSummary() {
|
|
166
|
+
return {
|
|
167
|
+
errors: this.errors.length,
|
|
168
|
+
warnings: this.warnings.length,
|
|
169
|
+
infos: this.infos.length,
|
|
170
|
+
logFile: this.logFile
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get the most recent errors (for preview)
|
|
176
|
+
*/
|
|
177
|
+
getRecentErrors(count = 3) {
|
|
178
|
+
return this.errors.slice(-count);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the most recent warnings (for preview)
|
|
183
|
+
*/
|
|
184
|
+
getRecentWarnings(count = 3) {
|
|
185
|
+
return this.warnings.slice(-count);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Display a summary to the console
|
|
190
|
+
*/
|
|
191
|
+
displaySummary() {
|
|
192
|
+
const summary = this.getSummary();
|
|
193
|
+
|
|
194
|
+
if (summary.errors > 0 || summary.warnings > 0) {
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(chalk.bold('Issues Summary:'));
|
|
197
|
+
|
|
198
|
+
if (summary.errors > 0) {
|
|
199
|
+
console.log(chalk.red(` ✗ ${summary.errors} error(s)`));
|
|
200
|
+
|
|
201
|
+
// Show preview of recent errors
|
|
202
|
+
const recentErrors = this.getRecentErrors(3);
|
|
203
|
+
recentErrors.forEach((err, idx) => {
|
|
204
|
+
console.log(chalk.red(` ${idx + 1}. ${err.message}`));
|
|
205
|
+
if (err.hint) {
|
|
206
|
+
console.log(chalk.yellow(` ${err.hint}`));
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (summary.errors > 3) {
|
|
211
|
+
console.log(chalk.gray(` ... and ${summary.errors - 3} more`));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (summary.warnings > 0) {
|
|
216
|
+
console.log(chalk.yellow(` ⚠ ${summary.warnings} warning(s)`));
|
|
217
|
+
|
|
218
|
+
// Show preview of recent warnings
|
|
219
|
+
const recentWarnings = this.getRecentWarnings(2);
|
|
220
|
+
recentWarnings.forEach((warn, idx) => {
|
|
221
|
+
console.log(chalk.yellow(` ${idx + 1}. ${warn.message}`));
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
if (summary.warnings > 2) {
|
|
225
|
+
console.log(chalk.gray(` ... and ${summary.warnings - 2} more`));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Only show log file path if logging is enabled
|
|
230
|
+
if (this.loggingEnabled) {
|
|
231
|
+
console.log('');
|
|
232
|
+
console.log(chalk.cyan(`📄 Full log: ${chalk.white(summary.logFile)}`));
|
|
233
|
+
console.log(chalk.gray(` View with: cat ${summary.logFile}`));
|
|
234
|
+
}
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Finalize the log file
|
|
241
|
+
*/
|
|
242
|
+
close() {
|
|
243
|
+
this.writeToFile('');
|
|
244
|
+
this.writeToFile(`Completed: ${new Date().toISOString()}`);
|
|
245
|
+
this.writeToFile(`Summary: ${this.errors.length} errors, ${this.warnings.length} warnings, ${this.infos.length} info messages`);
|
|
246
|
+
this.writeToFile('=== END LOG ===');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Clean up old log files (keep only last N logs)
|
|
251
|
+
*/
|
|
252
|
+
static cleanupOldLogs(keepCount = 10) {
|
|
253
|
+
const logDir = '.magentrix/logs';
|
|
254
|
+
|
|
255
|
+
if (!fs.existsSync(logDir)) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const files = fs.readdirSync(logDir)
|
|
261
|
+
.filter(f => f.endsWith('.log'))
|
|
262
|
+
.map(f => ({
|
|
263
|
+
name: f,
|
|
264
|
+
path: path.join(logDir, f),
|
|
265
|
+
time: fs.statSync(path.join(logDir, f)).mtime.getTime()
|
|
266
|
+
}))
|
|
267
|
+
.sort((a, b) => b.time - a.time); // Sort by newest first
|
|
268
|
+
|
|
269
|
+
// Delete files beyond keepCount
|
|
270
|
+
if (files.length > keepCount) {
|
|
271
|
+
const toDelete = files.slice(keepCount);
|
|
272
|
+
toDelete.forEach(file => {
|
|
273
|
+
try {
|
|
274
|
+
fs.unlinkSync(file.path);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
// Ignore errors when deleting old logs
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
// Ignore errors in cleanup
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Create a logger instance for an operation
|
|
288
|
+
*/
|
|
289
|
+
export function createLogger(operationName) {
|
|
290
|
+
return new Logger(operationName);
|
|
291
|
+
}
|