@loglayer/transport-pretty-terminal 4.0.4 → 4.1.0
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/dist/index.cjs +1607 -1758
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -153
- package/dist/index.d.ts +147 -153
- package/dist/index.js +1559 -1751
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -1,742 +1,698 @@
|
|
|
1
|
-
// src/PrettyTerminalTransport.ts
|
|
2
1
|
import { LoggerlessTransport } from "@loglayer/transport";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
// src/views/DetailView.ts
|
|
6
|
-
import chalk3 from "chalk";
|
|
2
|
+
import * as chalk from "chalk";
|
|
3
|
+
import chalk$1 from "chalk";
|
|
7
4
|
import wrap from "wrap-ansi";
|
|
5
|
+
import truncate from "cli-truncate";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import Database from "better-sqlite3";
|
|
8
|
+
import keypress from "keypress";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
//#region src/vendor/utils.js
|
|
11
|
+
/**
|
|
12
|
+
* Creates a string with the same length as `numSpaces` parameter
|
|
13
|
+
**/
|
|
13
14
|
function indent(numSpaces) {
|
|
14
|
-
|
|
15
|
+
return new Array(numSpaces + 1).join(" ");
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Gets the string length of the longer index in a hash
|
|
19
|
+
**/
|
|
16
20
|
function getMaxIndexLength(input) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
return maxWidth;
|
|
21
|
+
var maxWidth = 0;
|
|
22
|
+
Object.getOwnPropertyNames(input).forEach((key) => {
|
|
23
|
+
if (input[key] === void 0) return;
|
|
24
|
+
maxWidth = Math.max(maxWidth, key.length);
|
|
25
|
+
});
|
|
26
|
+
return maxWidth;
|
|
25
27
|
}
|
|
26
28
|
function isIsoStringDate(isoString) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
const testDate = new Date(isoString);
|
|
34
|
-
return !Number.isNaN(testDate.getTime());
|
|
29
|
+
if (typeof isoString !== "string") return false;
|
|
30
|
+
if (!/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/.test(isoString)) return false;
|
|
31
|
+
const testDate = new Date(isoString);
|
|
32
|
+
return !Number.isNaN(testDate.getTime());
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (Array.isArray(input) && isSerializable(input[0], true, options)) {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/vendor/prettyjson.js
|
|
37
|
+
const conflictChars = /[^\w\s\n\r\v\t.,]/i;
|
|
38
|
+
const isPrintable = (input, options) => input !== void 0 || options.renderUndefined;
|
|
39
|
+
const isSerializable = (input, onlyPrimitives, options) => {
|
|
40
|
+
if (typeof input === "boolean" || typeof input === "number" || typeof input === "function" || input === null || input === void 0 || input instanceof Date) return true;
|
|
41
|
+
if (typeof input === "string" && input.indexOf("\n") === -1) return true;
|
|
42
|
+
if (options.inlineArrays && !onlyPrimitives) {
|
|
43
|
+
if (Array.isArray(input) && isSerializable(input[0], true, options)) return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
53
46
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @param {Function} colorFn
|
|
49
|
+
* @param {PrettyJSONOptions} options
|
|
50
|
+
*/
|
|
51
|
+
const getColorRenderer = (colorFn, options) => {
|
|
52
|
+
if (options.noColor) return (text) => text;
|
|
53
|
+
if (typeof colorFn !== "function") return (text) => text;
|
|
54
|
+
return colorFn;
|
|
62
55
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (input === null || input === void 0) {
|
|
81
|
-
return getColorRenderer(options.nullUndefinedColor, options)(sInput);
|
|
82
|
-
}
|
|
83
|
-
if (typeof input === "number") {
|
|
84
|
-
if (input >= 0) {
|
|
85
|
-
return getColorRenderer(options.positiveNumberColor, options)(sInput);
|
|
86
|
-
}
|
|
87
|
-
return getColorRenderer(options.negativeNumberColor, options)(sInput);
|
|
88
|
-
}
|
|
89
|
-
if (typeof input === "function") {
|
|
90
|
-
return "function() {}";
|
|
91
|
-
}
|
|
92
|
-
if (Array.isArray(input)) {
|
|
93
|
-
return input.join(", ");
|
|
94
|
-
}
|
|
95
|
-
return sInput;
|
|
56
|
+
const addColorToData = (input, options) => {
|
|
57
|
+
if (options.noColor) return input;
|
|
58
|
+
if (input instanceof Date) return getColorRenderer(options.dateColor, options)(input.toISOString());
|
|
59
|
+
if (typeof input === "string") {
|
|
60
|
+
if (isIsoStringDate(input)) return getColorRenderer(options.dateColor, options)(input);
|
|
61
|
+
return getColorRenderer(options.stringColor, options)(input);
|
|
62
|
+
}
|
|
63
|
+
const sInput = `${input}`;
|
|
64
|
+
if (typeof input === "boolean") return getColorRenderer(options.booleanColor, options)(sInput);
|
|
65
|
+
if (input === null || input === void 0) return getColorRenderer(options.nullUndefinedColor, options)(sInput);
|
|
66
|
+
if (typeof input === "number") {
|
|
67
|
+
if (input >= 0) return getColorRenderer(options.positiveNumberColor, options)(sInput);
|
|
68
|
+
return getColorRenderer(options.negativeNumberColor, options)(sInput);
|
|
69
|
+
}
|
|
70
|
+
if (typeof input === "function") return "function() {}";
|
|
71
|
+
if (Array.isArray(input)) return input.join(", ");
|
|
72
|
+
return sInput;
|
|
96
73
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
74
|
+
const colorMultilineString = (options, line) => getColorRenderer(options.multilineStringColor, options)(line);
|
|
75
|
+
const indentLines = (string, spaces, options) => {
|
|
76
|
+
let lines = string.split("\n");
|
|
77
|
+
lines = lines.map((line) => indent(spaces) + colorMultilineString(options, line));
|
|
78
|
+
return lines.join("\n");
|
|
102
79
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
const maxIndexLength = options.noAlign ? 0 : getMaxIndexLength(data);
|
|
156
|
-
let key;
|
|
157
|
-
const output = [];
|
|
158
|
-
Object.getOwnPropertyNames(data).forEach((i) => {
|
|
159
|
-
if (!isPrintable(data[i], options)) {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
key = `${i}: `;
|
|
163
|
-
key = getColorRenderer(options.keysColor, options)(key);
|
|
164
|
-
key = indent(indentation) + key;
|
|
165
|
-
if (isSerializable(data[i], false, options)) {
|
|
166
|
-
const nextIndentation = options.noAlign ? 0 : maxIndexLength - i.length;
|
|
167
|
-
key += renderToArray(data[i], options, nextIndentation)[0];
|
|
168
|
-
output.push(key);
|
|
169
|
-
} else {
|
|
170
|
-
output.push(key);
|
|
171
|
-
output.push.apply(output, renderToArray(data[i], options, indentation + options.defaultIndentation));
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
return output;
|
|
80
|
+
const renderToArray = (data, options, indentation) => {
|
|
81
|
+
if (typeof data === "string" && data.match(conflictChars) && options.escape) data = JSON.stringify(data);
|
|
82
|
+
if (!isPrintable(data, options)) return [];
|
|
83
|
+
if (isSerializable(data, false, options)) return [indent(indentation) + addColorToData(data, options)];
|
|
84
|
+
if (typeof data === "string") return [
|
|
85
|
+
indent(indentation) + colorMultilineString(options, "\"\"\""),
|
|
86
|
+
indentLines(data, indentation + options.defaultIndentation, options),
|
|
87
|
+
indent(indentation) + colorMultilineString(options, "\"\"\"")
|
|
88
|
+
];
|
|
89
|
+
if (Array.isArray(data)) {
|
|
90
|
+
if (data.length === 0) return [indent(indentation) + options.emptyArrayMsg];
|
|
91
|
+
if (options.collapseArrays && data.length > 0) return [`${indent(indentation)}[... ${data.length} items]`];
|
|
92
|
+
const outputArray = [];
|
|
93
|
+
data.forEach((element) => {
|
|
94
|
+
if (!isPrintable(element, options)) return;
|
|
95
|
+
let line = "- ";
|
|
96
|
+
line = getColorRenderer(options.dashColor, options)(line);
|
|
97
|
+
line = indent(indentation) + line;
|
|
98
|
+
if (isSerializable(element, false, options)) {
|
|
99
|
+
line += renderToArray(element, options, 0)[0];
|
|
100
|
+
outputArray.push(line);
|
|
101
|
+
} else {
|
|
102
|
+
outputArray.push(line);
|
|
103
|
+
outputArray.push.apply(outputArray, renderToArray(element, options, indentation + options.defaultIndentation));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
return outputArray;
|
|
107
|
+
}
|
|
108
|
+
if (data instanceof Error) return renderToArray({
|
|
109
|
+
message: data.message,
|
|
110
|
+
stack: data.stack.split("\n")
|
|
111
|
+
}, options, indentation);
|
|
112
|
+
const maxIndexLength = options.noAlign ? 0 : getMaxIndexLength(data);
|
|
113
|
+
let key;
|
|
114
|
+
const output = [];
|
|
115
|
+
Object.getOwnPropertyNames(data).forEach((i) => {
|
|
116
|
+
if (!isPrintable(data[i], options)) return;
|
|
117
|
+
key = `${i}: `;
|
|
118
|
+
key = getColorRenderer(options.keysColor, options)(key);
|
|
119
|
+
key = indent(indentation) + key;
|
|
120
|
+
if (isSerializable(data[i], false, options)) {
|
|
121
|
+
const nextIndentation = options.noAlign ? 0 : maxIndexLength - i.length;
|
|
122
|
+
key += renderToArray(data[i], options, nextIndentation)[0];
|
|
123
|
+
output.push(key);
|
|
124
|
+
} else {
|
|
125
|
+
output.push(key);
|
|
126
|
+
output.push.apply(output, renderToArray(data[i], options, indentation + options.defaultIndentation));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
return output;
|
|
175
130
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
131
|
+
/**
|
|
132
|
+
* @typedef {Object} PrettyJSONOptions
|
|
133
|
+
* @property {Function} [stringColor=null] Chalk color function for strings
|
|
134
|
+
* @property {Function} [multilineStringColor=null] Chalk color function for multiline strings
|
|
135
|
+
* @property {Function} [keysColor=chalk.green] Chalk color function for keys in hashes
|
|
136
|
+
* @property {Function} [dashColor=chalk.green] Chalk color function for dashes in arrays
|
|
137
|
+
* @property {Function} [numberColor=chalk.blue] Default Chalk color function for numbers
|
|
138
|
+
* @property {Function} [positiveNumberColor=numberColor] Chalk color function for positive numbers
|
|
139
|
+
* @property {Function} [negativeNumberColor=numberColor] Chalk color function for negative numbers
|
|
140
|
+
* @property {Function} [booleanColor=chalk.cyan] Chalk color function for boolean values
|
|
141
|
+
* @property {Function} [nullUndefinedColor=chalk.grey] Chalk color function for null || undefined
|
|
142
|
+
* @property {Function} [dateColor=chalk.magenta] Chalk color function for Date objects
|
|
143
|
+
* @property {number} [defaultIndentation=2] Indentation spaces per object level
|
|
144
|
+
* @property {string} [emptyArrayMsg="(empty array)"] Replace empty strings with
|
|
145
|
+
* @property {boolean} [noColor] Flag to disable colors
|
|
146
|
+
* @property {boolean} [noAlign] Flag to disable alignment
|
|
147
|
+
* @property {boolean} [escape] Flag to escape printed content
|
|
148
|
+
* @property {boolean} [collapseArrays] Flag to collapse arrays
|
|
149
|
+
*/
|
|
150
|
+
/**
|
|
151
|
+
* Mutating function that ensures we have a valid options object
|
|
152
|
+
* @param {PrettyJSONOptions} options
|
|
153
|
+
* @returns PrettyJSONOptions
|
|
154
|
+
*/
|
|
155
|
+
const validateOptionsAndSetDefaults = (options) => {
|
|
156
|
+
options = options || {};
|
|
157
|
+
options.emptyArrayMsg = options.emptyArrayMsg || "(empty array)";
|
|
158
|
+
options.keysColor = options.keysColor || chalk$1.green;
|
|
159
|
+
options.dashColor = options.dashColor || chalk$1.green;
|
|
160
|
+
options.booleanColor = options.booleanColor || chalk$1.cyan;
|
|
161
|
+
options.nullUndefinedColor = options.nullUndefinedColor || chalk$1.grey;
|
|
162
|
+
options.numberColor = options.numberColor || chalk$1.blue;
|
|
163
|
+
options.positiveNumberColor = options.positiveNumberColor || options.numberColor;
|
|
164
|
+
options.negativeNumberColor = options.negativeNumberColor || options.numberColor;
|
|
165
|
+
options.dateColor = options.dateColor || chalk$1.magenta;
|
|
166
|
+
options.defaultIndentation = options.defaultIndentation || 2;
|
|
167
|
+
options.noColor = !!options.noColor;
|
|
168
|
+
options.noAlign = !!options.noAlign;
|
|
169
|
+
options.escape = !!options.escape;
|
|
170
|
+
options.renderUndefined = !!options.renderUndefined;
|
|
171
|
+
options.collapseArrays = !!options.collapseArrays;
|
|
172
|
+
options.stringColor = options.stringColor || null;
|
|
173
|
+
options.multilineStringColor = options.multilineStringColor || options.stringColor || null;
|
|
174
|
+
return options;
|
|
196
175
|
};
|
|
176
|
+
/**
|
|
177
|
+
* ### Render function
|
|
178
|
+
* *Parameters:*
|
|
179
|
+
*
|
|
180
|
+
* @param {*} data: Data to render
|
|
181
|
+
* @param {PrettyJSONOptions} options: Hash of different options
|
|
182
|
+
* @param {*} indentation **`indentation`**: Base indentation of the output
|
|
183
|
+
*
|
|
184
|
+
* *Example of options hash:*
|
|
185
|
+
*
|
|
186
|
+
* {
|
|
187
|
+
* emptyArrayMsg: '(empty)', // Rendered message on empty strings
|
|
188
|
+
* keysColor: 'blue', // Color for keys in hashes
|
|
189
|
+
* dashColor: 'red', // Color for the dashes in arrays
|
|
190
|
+
* stringColor: 'grey', // Color for strings
|
|
191
|
+
* multilineStringColor: 'cyan' // Color for multiline strings
|
|
192
|
+
* defaultIndentation: 2 // Indentation on nested objects
|
|
193
|
+
* }
|
|
194
|
+
* @returns string with the rendered data
|
|
195
|
+
*/
|
|
197
196
|
function render(data, options, indentation) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
197
|
+
indentation = indentation || 0;
|
|
198
|
+
options = validateOptionsAndSetDefaults(options);
|
|
199
|
+
return renderToArray(data, options, indentation).join("\n");
|
|
201
200
|
}
|
|
202
201
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/views/utils.ts
|
|
204
|
+
/**
|
|
205
|
+
* Formats a timestamp into a human-readable string.
|
|
206
|
+
* Format: HH:MM:SS.mmm
|
|
207
|
+
*/
|
|
206
208
|
function formatTimestamp(timestamp, colorFn) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
`${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}.${date.getMilliseconds().toString().padStart(3, "0")}`
|
|
210
|
-
);
|
|
209
|
+
const date = new Date(timestamp);
|
|
210
|
+
return colorFn(`${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}.${date.getMilliseconds().toString().padStart(3, "0")}`);
|
|
211
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Gets the color function for a log level.
|
|
214
|
+
*/
|
|
212
215
|
function getLevelColor(level, colors) {
|
|
213
|
-
|
|
216
|
+
return colors[level] || chalk$1.white;
|
|
214
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Formats a value for display.
|
|
220
|
+
*/
|
|
215
221
|
function formatValue(value, expanded = false) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
if (typeof value === "string") return value;
|
|
223
|
+
if (typeof value === "number" || typeof value === "boolean") return value.toString();
|
|
224
|
+
if (value === null) return "null";
|
|
225
|
+
if (value === void 0) return "undefined";
|
|
226
|
+
if (Array.isArray(value)) return expanded ? JSON.stringify(value) : "[...]";
|
|
227
|
+
if (typeof value === "object") return expanded ? JSON.stringify(value) : "{...}";
|
|
228
|
+
return value.toString();
|
|
223
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Formats structured data for inline display with depth limiting.
|
|
232
|
+
*/
|
|
224
233
|
function formatInlineData(data, config, maxDepth, maxLength, expanded = false) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
|
-
traverse(data);
|
|
243
|
-
const result = pairs.join(" ");
|
|
244
|
-
return expanded ? result : truncate(result, maxLength);
|
|
234
|
+
if (!data) return "";
|
|
235
|
+
const pairs = [];
|
|
236
|
+
const traverse = (obj, prefix = "", depth = 0) => {
|
|
237
|
+
if (!expanded && depth >= maxDepth) return;
|
|
238
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
239
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
240
|
+
if (value && typeof value === "object" && !Array.isArray(value)) if (expanded) pairs.push(`${config.dataKeyColor(fullKey)}=${config.dataValueColor(JSON.stringify(value))}`);
|
|
241
|
+
else traverse(value, fullKey, depth + 1);
|
|
242
|
+
else pairs.push(`${config.dataKeyColor(fullKey)}=${config.dataValueColor(formatValue(value, expanded))}`);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
traverse(data);
|
|
246
|
+
const result = pairs.join(" ");
|
|
247
|
+
return expanded ? result : truncate(result, maxLength);
|
|
245
248
|
}
|
|
246
249
|
|
|
247
|
-
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/views/DetailView.ts
|
|
252
|
+
/**
|
|
253
|
+
* Handles rendering of the detail view mode.
|
|
254
|
+
* Shows a full-screen view of a single log entry with:
|
|
255
|
+
* - Previous/next log context
|
|
256
|
+
* - Full timestamp information
|
|
257
|
+
* - Pretty-printed data
|
|
258
|
+
* - Navigation help
|
|
259
|
+
*/
|
|
248
260
|
var DetailView = class {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const topPadding = 2;
|
|
354
|
-
const availableHeight = Math.max(
|
|
355
|
-
0,
|
|
356
|
-
process.stdout.rows - headerHeight - footerHeight - scrollIndicatorLines - bufferSpace - topPadding
|
|
357
|
-
);
|
|
358
|
-
for (const line of headerContent) {
|
|
359
|
-
console.log(line);
|
|
360
|
-
}
|
|
361
|
-
if (this.config.scrollPos > 0) {
|
|
362
|
-
console.log(chalk3.dim("\u2191 More content above"));
|
|
363
|
-
}
|
|
364
|
-
const startIndex = this.config.scrollPos;
|
|
365
|
-
const visibleContent = mainContent.slice(startIndex, startIndex + availableHeight);
|
|
366
|
-
for (const line of visibleContent) {
|
|
367
|
-
console.log(line);
|
|
368
|
-
}
|
|
369
|
-
if (this.config.scrollPos + availableHeight < mainContent.length) {
|
|
370
|
-
console.log(chalk3.dim("\u2193 More content below"));
|
|
371
|
-
} else {
|
|
372
|
-
console.log(chalk3.dim("End of content"));
|
|
373
|
-
}
|
|
374
|
-
for (const line of footerContent) {
|
|
375
|
-
console.log(line);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Gets the maximum scroll position based on current content and window size
|
|
380
|
-
*/
|
|
381
|
-
getMaxScrollPosition() {
|
|
382
|
-
const headerHeight = this.config.prevEntry ? 2 : 0;
|
|
383
|
-
const footerHeight = 5;
|
|
384
|
-
const scrollIndicatorLines = 2;
|
|
385
|
-
const bufferSpace = 2;
|
|
386
|
-
const topPadding = 2;
|
|
387
|
-
const availableHeight = Math.max(
|
|
388
|
-
0,
|
|
389
|
-
process.stdout.rows - headerHeight - footerHeight - scrollIndicatorLines - bufferSpace - topPadding
|
|
390
|
-
);
|
|
391
|
-
return Math.max(0, this.detailViewContent.length - availableHeight);
|
|
392
|
-
}
|
|
261
|
+
termWidth;
|
|
262
|
+
config;
|
|
263
|
+
detailViewContent = [];
|
|
264
|
+
constructor(config) {
|
|
265
|
+
this.config = config;
|
|
266
|
+
this.termWidth = process.stdout.columns || 80;
|
|
267
|
+
}
|
|
268
|
+
updateTerminalWidth(width) {
|
|
269
|
+
this.termWidth = width;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Formats a compact single-line version of a log entry
|
|
273
|
+
*/
|
|
274
|
+
formatCompactLogLine(entry, prefix = "") {
|
|
275
|
+
if (!entry) return "";
|
|
276
|
+
const levelColor = getLevelColor(entry.level, this.config.config.colors);
|
|
277
|
+
const logId = this.config.config.logIdColor(`[${entry.id}]`);
|
|
278
|
+
const line = `${prefix}${levelColor(entry.level.toUpperCase())} ${logId} ${entry.message}`;
|
|
279
|
+
return this.config.config.separatorColor(wrap(line, this.termWidth, { hard: true }));
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Formats a timestamp into a human-readable relative time
|
|
283
|
+
*/
|
|
284
|
+
formatRelativeTime(timestamp) {
|
|
285
|
+
const diffMs = (/* @__PURE__ */ new Date()).getTime() - timestamp.getTime();
|
|
286
|
+
const diffSecs = Math.floor(diffMs / 1e3);
|
|
287
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
288
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
289
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
290
|
+
if (diffSecs < 60) return `${diffSecs}s ago`;
|
|
291
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
292
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
293
|
+
if (diffDays === 1) return "yesterday";
|
|
294
|
+
if (diffDays < 30) return `${diffDays}d ago`;
|
|
295
|
+
return timestamp.toLocaleDateString();
|
|
296
|
+
}
|
|
297
|
+
render() {
|
|
298
|
+
console.clear();
|
|
299
|
+
console.log("\n".repeat(5));
|
|
300
|
+
if (this.config.isJsonView) {
|
|
301
|
+
if (this.config.entry.data) console.log(JSON.stringify(JSON.parse(this.config.entry.data)));
|
|
302
|
+
else console.log("{}");
|
|
303
|
+
console.log(`\n${this.config.config.separatorColor("TAB to return to detailed view")}`);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const headerContent = [];
|
|
307
|
+
if (this.config.prevEntry) {
|
|
308
|
+
const prevLine = this.formatCompactLogLine(this.config.prevEntry, "← ");
|
|
309
|
+
headerContent.push(prevLine);
|
|
310
|
+
headerContent.push(this.config.config.separatorColor("─".repeat(this.termWidth)));
|
|
311
|
+
}
|
|
312
|
+
const footerContent = [];
|
|
313
|
+
if (this.config.nextEntry) {
|
|
314
|
+
footerContent.push(this.config.config.separatorColor("─".repeat(this.termWidth)));
|
|
315
|
+
const nextLine = this.formatCompactLogLine(this.config.nextEntry, "→ ");
|
|
316
|
+
footerContent.push(nextLine);
|
|
317
|
+
}
|
|
318
|
+
footerContent.push("");
|
|
319
|
+
footerContent.push(this.config.config.separatorColor("↑/↓ scroll • Q/W page up/down • J raw JSON"));
|
|
320
|
+
footerContent.push(this.config.config.separatorColor("←/→ navigate • A/S first/last log • C toggle arrays"));
|
|
321
|
+
const mainContent = [];
|
|
322
|
+
const levelColor = getLevelColor(this.config.entry.level, this.config.config.colors);
|
|
323
|
+
let headerText = `=== Log Detail [${this.config.entry.id}] (${this.config.currentLogIndex} / ${this.config.totalLogs})`;
|
|
324
|
+
if (this.config.filterText) headerText += ` [Filter: ${this.config.filterText}]`;
|
|
325
|
+
headerText += " ===";
|
|
326
|
+
const header = levelColor(headerText);
|
|
327
|
+
mainContent.push(header);
|
|
328
|
+
const timestamp = new Date(this.config.entry.timestamp);
|
|
329
|
+
const isoTime = formatTimestamp(this.config.entry.timestamp, this.config.config.dataValueColor);
|
|
330
|
+
const relativeTime = this.formatRelativeTime(timestamp);
|
|
331
|
+
mainContent.push(`${this.config.config.labelColor("Timestamp:")} ${isoTime} (${relativeTime})`);
|
|
332
|
+
mainContent.push(`${this.config.config.labelColor("Level:")} ${levelColor.bold(this.config.entry.level.toUpperCase())}`);
|
|
333
|
+
if (this.config.entry.message) mainContent.push(`${this.config.config.labelColor("Message:")} ${this.config.config.dataValueColor(this.config.entry.message)}`);
|
|
334
|
+
else mainContent.push(`${this.config.config.labelColor("Message:")} ${this.config.config.dataValueColor.dim("(no message)")}`);
|
|
335
|
+
if (this.config.entry.data) {
|
|
336
|
+
mainContent.push(this.config.config.labelColor("\nData:"));
|
|
337
|
+
const jsonLines = render(JSON.parse(this.config.entry.data), {
|
|
338
|
+
...this.config.config.jsonColors,
|
|
339
|
+
defaultIndentation: 2,
|
|
340
|
+
collapseArrays: this.config.isArraysCollapsed
|
|
341
|
+
}).split("\n");
|
|
342
|
+
mainContent.push(...jsonLines);
|
|
343
|
+
}
|
|
344
|
+
this.detailViewContent = mainContent;
|
|
345
|
+
const headerHeight = headerContent.length;
|
|
346
|
+
const footerHeight = footerContent.length;
|
|
347
|
+
const availableHeight = Math.max(0, process.stdout.rows - headerHeight - footerHeight - 2 - 4 - 2);
|
|
348
|
+
for (const line of headerContent) console.log(line);
|
|
349
|
+
if (this.config.scrollPos > 0) console.log(chalk$1.dim("↑ More content above"));
|
|
350
|
+
const startIndex = this.config.scrollPos;
|
|
351
|
+
const visibleContent = mainContent.slice(startIndex, startIndex + availableHeight);
|
|
352
|
+
for (const line of visibleContent) console.log(line);
|
|
353
|
+
if (this.config.scrollPos + availableHeight < mainContent.length) console.log(chalk$1.dim("↓ More content below"));
|
|
354
|
+
else console.log(chalk$1.dim("End of content"));
|
|
355
|
+
for (const line of footerContent) console.log(line);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Gets the maximum scroll position based on current content and window size
|
|
359
|
+
*/
|
|
360
|
+
getMaxScrollPosition() {
|
|
361
|
+
const headerHeight = this.config.prevEntry ? 2 : 0;
|
|
362
|
+
const availableHeight = Math.max(0, process.stdout.rows - headerHeight - 5 - 2 - 2 - 2);
|
|
363
|
+
return Math.max(0, this.detailViewContent.length - availableHeight);
|
|
364
|
+
}
|
|
393
365
|
};
|
|
394
366
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/views/SelectionView.ts
|
|
369
|
+
/**
|
|
370
|
+
* Handles rendering of the selection view mode.
|
|
371
|
+
* Shows an interactive list of logs with:
|
|
372
|
+
* - Filtering capability
|
|
373
|
+
* - Selected item highlighting
|
|
374
|
+
* - Full data preview inline
|
|
375
|
+
* - Scroll indicators
|
|
376
|
+
*/
|
|
398
377
|
var SelectionView = class {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (isSelected) {
|
|
441
|
-
const lines = wrappedText.split("\n");
|
|
442
|
-
console.log(lines[0]);
|
|
443
|
-
for (const line of lines.slice(1)) {
|
|
444
|
-
console.log(` ${this.config.config.selectorColor("\u2502")} ${line}`);
|
|
445
|
-
}
|
|
446
|
-
} else {
|
|
447
|
-
console.log(wrappedText);
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
if (endIdx < this.config.logs.length || this.config.newLogCount > 0) {
|
|
451
|
-
const moreLogsText = this.config.newLogCount > 0 ? this.config.config.selectorColor(
|
|
452
|
-
` \u2193 ${this.config.newLogCount} new log${this.config.newLogCount === 1 ? "" : "s"} available (press \u2193 to view)`
|
|
453
|
-
) : chalk4.dim(" \u2193 More logs below");
|
|
454
|
-
console.log(moreLogsText);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
console.log(chalk4.dim("\nType to filter \u2022 Enter to view details \u2022 TAB to exit"));
|
|
458
|
-
if (this.config.filterText) {
|
|
459
|
-
console.log(chalk4.dim("\u2500".repeat(this.termWidth)));
|
|
460
|
-
console.log(chalk4.cyan("Filter:"), chalk4.white(this.config.filterText));
|
|
461
|
-
}
|
|
462
|
-
}
|
|
378
|
+
termWidth;
|
|
379
|
+
config;
|
|
380
|
+
constructor(config) {
|
|
381
|
+
this.config = config;
|
|
382
|
+
this.termWidth = process.stdout.columns || 80;
|
|
383
|
+
}
|
|
384
|
+
updateTerminalWidth(width) {
|
|
385
|
+
this.termWidth = width;
|
|
386
|
+
}
|
|
387
|
+
render() {
|
|
388
|
+
console.clear();
|
|
389
|
+
console.log("\n".repeat(5));
|
|
390
|
+
const filterHeight = this.config.filterText ? 2 : 0;
|
|
391
|
+
const availableHeight = process.stdout.rows - filterHeight - 2 - 5;
|
|
392
|
+
if (this.config.logs.length === 0) console.log(chalk$1.yellow("No matching logs found"));
|
|
393
|
+
else {
|
|
394
|
+
const visibleLines = Math.min(availableHeight, 20);
|
|
395
|
+
let startIdx = Math.max(0, this.config.selectedIndex - (visibleLines - 2 - 1));
|
|
396
|
+
const endIdx = Math.min(this.config.logs.length, startIdx + visibleLines);
|
|
397
|
+
if (endIdx - startIdx < visibleLines && endIdx < this.config.logs.length) startIdx = Math.max(0, endIdx - visibleLines);
|
|
398
|
+
if (startIdx > 0) console.log(chalk$1.dim(" ↑ More logs above"));
|
|
399
|
+
this.config.logs.slice(startIdx, endIdx).forEach((entry, index) => {
|
|
400
|
+
const isSelected = startIdx + index === this.config.selectedIndex;
|
|
401
|
+
const wrappedText = wrap(`${isSelected ? this.config.config.selectorColor("► ") : " "}${formatTimestamp(entry.timestamp, this.config.config.logIdColor)} ${getLevelColor(entry.level, this.config.config.colors)(`${entry.level.toUpperCase()} `)}${chalk$1.dim(`[${entry.id}]`)} ${entry.message}${entry.data ? ` ${formatInlineData(JSON.parse(entry.data), this.config.config, 0, 0, true)}` : ""}`, this.termWidth - 2, { hard: true });
|
|
402
|
+
if (isSelected) {
|
|
403
|
+
const lines = wrappedText.split("\n");
|
|
404
|
+
console.log(lines[0]);
|
|
405
|
+
for (const line of lines.slice(1)) console.log(` ${this.config.config.selectorColor("│")} ${line}`);
|
|
406
|
+
} else console.log(wrappedText);
|
|
407
|
+
});
|
|
408
|
+
if (endIdx < this.config.logs.length || this.config.newLogCount > 0) {
|
|
409
|
+
const moreLogsText = this.config.newLogCount > 0 ? this.config.config.selectorColor(` ↓ ${this.config.newLogCount} new log${this.config.newLogCount === 1 ? "" : "s"} available (press ↓ to view)`) : chalk$1.dim(" ↓ More logs below");
|
|
410
|
+
console.log(moreLogsText);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
console.log(chalk$1.dim("\nType to filter • Enter to view details • TAB to exit"));
|
|
414
|
+
if (this.config.filterText) {
|
|
415
|
+
console.log(chalk$1.dim("─".repeat(this.termWidth)));
|
|
416
|
+
console.log(chalk$1.cyan("Filter:"), chalk$1.white(this.config.filterText));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
463
419
|
};
|
|
464
420
|
|
|
465
|
-
|
|
466
|
-
|
|
421
|
+
//#endregion
|
|
422
|
+
//#region src/views/SimpleView.ts
|
|
423
|
+
/**
|
|
424
|
+
* Handles rendering of the simple view mode.
|
|
425
|
+
* Supports three display modes:
|
|
426
|
+
* - Truncated: Shows all log details with truncated data
|
|
427
|
+
* - Condensed: Shows timestamp, level and message
|
|
428
|
+
* - Full: Shows all details with complete data
|
|
429
|
+
*/
|
|
467
430
|
var SimpleView = class {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
this.config.maxInlineDepth,
|
|
510
|
-
this.config.maxInlineLength
|
|
511
|
-
) : "";
|
|
512
|
-
const normalLine = `${timestamp} ${chevron}${logId} ${message}${normalData ? ` ${normalData}` : ""}`;
|
|
513
|
-
console.log(wrap3(normalLine, this.termWidth, { hard: true }));
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
render() {
|
|
519
|
-
throw new Error("SimpleView.render() should not be called directly. Use renderLogLine() instead.");
|
|
520
|
-
}
|
|
431
|
+
termWidth;
|
|
432
|
+
config;
|
|
433
|
+
constructor(config) {
|
|
434
|
+
this.config = config;
|
|
435
|
+
this.termWidth = process.stdout.columns || 80;
|
|
436
|
+
}
|
|
437
|
+
updateTerminalWidth(width) {
|
|
438
|
+
this.termWidth = width;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Renders a single log entry based on the current view mode
|
|
442
|
+
*/
|
|
443
|
+
renderLogLine(entry) {
|
|
444
|
+
const chevron = getLevelColor(entry.level, this.config.config.colors)(`▶ ${entry.level.toUpperCase()} `);
|
|
445
|
+
const message = entry.message || "(no message)";
|
|
446
|
+
const timestamp = formatTimestamp(entry.timestamp, this.config.config.logIdColor);
|
|
447
|
+
switch (this.config.viewMode) {
|
|
448
|
+
case "condensed": {
|
|
449
|
+
const condensedLine = `${timestamp} ${chevron}${message}`;
|
|
450
|
+
console.log(wrap(condensedLine, this.termWidth, { hard: true }));
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case "full": {
|
|
454
|
+
const logId = this.config.config.logIdColor(`[${entry.id}]`);
|
|
455
|
+
const fullData = entry.data ? formatInlineData(JSON.parse(entry.data), this.config.config, this.config.maxInlineDepth, this.config.maxInlineLength, true) : "";
|
|
456
|
+
const expandedLine = `${timestamp} ${chevron}${logId} ${message}${fullData ? ` ${fullData}` : ""}`;
|
|
457
|
+
console.log(wrap(expandedLine, this.termWidth, { hard: true }));
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
default: {
|
|
461
|
+
const logId = this.config.config.logIdColor(`[${entry.id}]`);
|
|
462
|
+
const normalData = entry.data ? formatInlineData(JSON.parse(entry.data), this.config.config, this.config.maxInlineDepth, this.config.maxInlineLength) : "";
|
|
463
|
+
const normalLine = `${timestamp} ${chevron}${logId} ${message}${normalData ? ` ${normalData}` : ""}`;
|
|
464
|
+
console.log(wrap(normalLine, this.termWidth, { hard: true }));
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
render() {
|
|
470
|
+
throw new Error("SimpleView.render() should not be called directly. Use renderLogLine() instead.");
|
|
471
|
+
}
|
|
521
472
|
};
|
|
522
473
|
|
|
523
|
-
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/LogRenderer.ts
|
|
476
|
+
/**
|
|
477
|
+
* LogRenderer coordinates between different view modes and manages the overall rendering state.
|
|
478
|
+
* Delegates actual rendering to specialized view implementations:
|
|
479
|
+
* - SimpleView: For real-time log output
|
|
480
|
+
* - SelectionView: For interactive log browsing
|
|
481
|
+
* - DetailView: For in-depth log inspection
|
|
482
|
+
*/
|
|
524
483
|
var LogRenderer = class {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
maxInlineDepth: this.maxInlineDepth,
|
|
700
|
-
maxInlineLength: this.maxInlineLength,
|
|
701
|
-
config: this.simpleViewConfig
|
|
702
|
-
});
|
|
703
|
-
return this.viewMode;
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Gets current view mode
|
|
707
|
-
*/
|
|
708
|
-
getViewMode() {
|
|
709
|
-
return this.viewMode;
|
|
710
|
-
}
|
|
484
|
+
/** Current terminal width in characters */
|
|
485
|
+
termWidth;
|
|
486
|
+
/** Maximum depth for displaying nested objects inline */
|
|
487
|
+
maxInlineDepth;
|
|
488
|
+
/** Maximum length for inline data before truncating */
|
|
489
|
+
maxInlineLength;
|
|
490
|
+
/** Whether arrays are currently collapsed in detail view */
|
|
491
|
+
isArraysCollapsed = true;
|
|
492
|
+
/** Current view mode in simple mode */
|
|
493
|
+
viewMode = "full";
|
|
494
|
+
/** Color and formatting config for simple log view */
|
|
495
|
+
simpleViewConfig;
|
|
496
|
+
/** Color and formatting config for detailed view */
|
|
497
|
+
detailedViewConfig;
|
|
498
|
+
/** Whether we're showing raw JSON view */
|
|
499
|
+
isJsonView = false;
|
|
500
|
+
/** Current scroll position in detailed view */
|
|
501
|
+
detailViewScrollPos = 0;
|
|
502
|
+
/** View instances */
|
|
503
|
+
simpleView;
|
|
504
|
+
detailView = null;
|
|
505
|
+
selectionView = null;
|
|
506
|
+
/**
|
|
507
|
+
* Creates a new LogRenderer instance.
|
|
508
|
+
*
|
|
509
|
+
* @param simpleViewConfig - Configuration for simple log view
|
|
510
|
+
* @param detailedViewConfig - Configuration for detailed view
|
|
511
|
+
* @param maxInlineDepth - Maximum depth for inline object display
|
|
512
|
+
* @param maxInlineLength - Maximum length before truncation
|
|
513
|
+
*/
|
|
514
|
+
constructor(simpleViewConfig, detailedViewConfig, maxInlineDepth, maxInlineLength) {
|
|
515
|
+
this.simpleViewConfig = simpleViewConfig;
|
|
516
|
+
this.detailedViewConfig = detailedViewConfig;
|
|
517
|
+
this.maxInlineDepth = maxInlineDepth;
|
|
518
|
+
this.maxInlineLength = maxInlineLength;
|
|
519
|
+
this.termWidth = process.stdout.columns || 80;
|
|
520
|
+
this.simpleView = new SimpleView({
|
|
521
|
+
viewMode: this.viewMode,
|
|
522
|
+
maxInlineDepth: this.maxInlineDepth,
|
|
523
|
+
maxInlineLength: this.maxInlineLength,
|
|
524
|
+
config: this.simpleViewConfig
|
|
525
|
+
});
|
|
526
|
+
this.detailView = null;
|
|
527
|
+
this.selectionView = null;
|
|
528
|
+
process.stdout.on("resize", () => {
|
|
529
|
+
this.termWidth = process.stdout.columns || 80;
|
|
530
|
+
this.simpleView.updateTerminalWidth(this.termWidth);
|
|
531
|
+
if (this.detailView) this.detailView.updateTerminalWidth(this.termWidth);
|
|
532
|
+
if (this.selectionView) this.selectionView.updateTerminalWidth(this.termWidth);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Renders a single log line in simple view format.
|
|
537
|
+
* Format: [timestamp] LEVEL [id] message data
|
|
538
|
+
* Condensed Format: [timestamp] LEVEL message
|
|
539
|
+
* Expanded Format: [timestamp] LEVEL [id] message full_data
|
|
540
|
+
*
|
|
541
|
+
* @param entry - Log entry to render
|
|
542
|
+
*/
|
|
543
|
+
renderLogLine(entry) {
|
|
544
|
+
this.simpleView.renderLogLine(entry);
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Renders the detailed view of a log entry.
|
|
548
|
+
* Shows full entry details with context and formatted data.
|
|
549
|
+
*
|
|
550
|
+
* @param entry - Log entry to show in detail
|
|
551
|
+
* @param prevEntry - Previous entry for context
|
|
552
|
+
* @param nextEntry - Next entry for context
|
|
553
|
+
* @param scrollPos - Current scroll position
|
|
554
|
+
* @param currentLogIndex - Current log index (optional)
|
|
555
|
+
* @param totalLogs - Total logs count (optional)
|
|
556
|
+
* @param filterText - Current filter text (if any)
|
|
557
|
+
*/
|
|
558
|
+
renderDetailView(entry, prevEntry, nextEntry, scrollPos = 0, currentLogIndex, totalLogs, filterText = "") {
|
|
559
|
+
const config = {
|
|
560
|
+
entry,
|
|
561
|
+
prevEntry,
|
|
562
|
+
nextEntry,
|
|
563
|
+
scrollPos,
|
|
564
|
+
isArraysCollapsed: this.isArraysCollapsed,
|
|
565
|
+
isJsonView: this.isJsonView,
|
|
566
|
+
currentLogIndex: currentLogIndex ?? (prevEntry ? 2 : nextEntry ? 1 : 1),
|
|
567
|
+
totalLogs: totalLogs ?? 1,
|
|
568
|
+
filterText,
|
|
569
|
+
config: this.detailedViewConfig
|
|
570
|
+
};
|
|
571
|
+
if (!this.detailView) this.detailView = new DetailView(config);
|
|
572
|
+
else this.detailView = new DetailView(config);
|
|
573
|
+
this.detailView.render();
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Updates the scroll position in detailed view
|
|
577
|
+
* @param delta - Number of lines to scroll
|
|
578
|
+
*/
|
|
579
|
+
scrollDetailView(delta) {
|
|
580
|
+
if (!this.detailView) return;
|
|
581
|
+
const maxScroll = this.detailView.getMaxScrollPosition();
|
|
582
|
+
this.detailViewScrollPos = Math.max(0, Math.min(maxScroll, this.detailViewScrollPos + delta));
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Gets the current scroll position
|
|
586
|
+
*/
|
|
587
|
+
getDetailViewScrollPos() {
|
|
588
|
+
return this.detailViewScrollPos;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Renders the selection view with a list of logs.
|
|
592
|
+
* Shows filtered logs with selection highlight and data preview.
|
|
593
|
+
*
|
|
594
|
+
* @param logs - Array of logs to display
|
|
595
|
+
* @param selectedIndex - Index of currently selected log
|
|
596
|
+
* @param filterText - Current filter text (if any)
|
|
597
|
+
* @param newLogCount - Number of new logs available
|
|
598
|
+
*/
|
|
599
|
+
renderSelectionView(logs, selectedIndex, filterText, newLogCount) {
|
|
600
|
+
const config = {
|
|
601
|
+
logs,
|
|
602
|
+
selectedIndex,
|
|
603
|
+
filterText,
|
|
604
|
+
newLogCount,
|
|
605
|
+
config: this.detailedViewConfig
|
|
606
|
+
};
|
|
607
|
+
if (!this.selectionView) this.selectionView = new SelectionView(config);
|
|
608
|
+
else this.selectionView = new SelectionView(config);
|
|
609
|
+
this.selectionView.render();
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Toggles JSON view state
|
|
613
|
+
*/
|
|
614
|
+
toggleJsonView() {
|
|
615
|
+
this.isJsonView = !this.isJsonView;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Gets current JSON view state
|
|
619
|
+
*/
|
|
620
|
+
isInJsonView() {
|
|
621
|
+
return this.isJsonView;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Toggles array collapse state in detail view
|
|
625
|
+
*/
|
|
626
|
+
toggleArrayCollapse() {
|
|
627
|
+
this.isArraysCollapsed = !this.isArraysCollapsed;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Cycles through view modes: full -> truncated -> condensed
|
|
631
|
+
*/
|
|
632
|
+
cycleViewMode() {
|
|
633
|
+
switch (this.viewMode) {
|
|
634
|
+
case "full":
|
|
635
|
+
this.viewMode = "truncated";
|
|
636
|
+
break;
|
|
637
|
+
case "truncated":
|
|
638
|
+
this.viewMode = "condensed";
|
|
639
|
+
break;
|
|
640
|
+
case "condensed":
|
|
641
|
+
this.viewMode = "full";
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
this.simpleView = new SimpleView({
|
|
645
|
+
viewMode: this.viewMode,
|
|
646
|
+
maxInlineDepth: this.maxInlineDepth,
|
|
647
|
+
maxInlineLength: this.maxInlineLength,
|
|
648
|
+
config: this.simpleViewConfig
|
|
649
|
+
});
|
|
650
|
+
return this.viewMode;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Gets current view mode
|
|
654
|
+
*/
|
|
655
|
+
getViewMode() {
|
|
656
|
+
return this.viewMode;
|
|
657
|
+
}
|
|
711
658
|
};
|
|
712
659
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/LogStorage.ts
|
|
662
|
+
/**
|
|
663
|
+
* Handles storage and retrieval of log entries using SQLite.
|
|
664
|
+
* Uses an in-memory database for optimal performance and automatic cleanup.
|
|
665
|
+
*
|
|
666
|
+
* The database schema includes:
|
|
667
|
+
* - id: Unique identifier for each log
|
|
668
|
+
* - timestamp: Unix timestamp in milliseconds
|
|
669
|
+
* - level: Log level (trace, debug, info, etc.)
|
|
670
|
+
* - message: Main log message
|
|
671
|
+
* - data: Optional structured data as JSON string
|
|
672
|
+
*/
|
|
716
673
|
var LogStorage = class {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
this.db.exec(`
|
|
674
|
+
/** SQLite database instance */
|
|
675
|
+
db;
|
|
676
|
+
/**
|
|
677
|
+
* Creates a new LogStorage instance.
|
|
678
|
+
* Initializes a SQLite database and creates the logs table.
|
|
679
|
+
*
|
|
680
|
+
* @param logFile - Optional path to SQLite file for persistent storage.
|
|
681
|
+
* If not provided, uses in-memory database.
|
|
682
|
+
* Relative paths are resolved from the current working directory.
|
|
683
|
+
*/
|
|
684
|
+
constructor(logFile) {
|
|
685
|
+
this.db = new Database(logFile ? logFile.startsWith("/") ? logFile : resolve(process.cwd(), logFile) : ":memory:");
|
|
686
|
+
this.initializeDatabase();
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Initializes the database schema.
|
|
690
|
+
* Creates the logs table with appropriate columns and indexes.
|
|
691
|
+
* If the table already exists, it will be dropped to ensure a clean state.
|
|
692
|
+
* @private
|
|
693
|
+
*/
|
|
694
|
+
initializeDatabase() {
|
|
695
|
+
this.db.exec(`
|
|
740
696
|
DROP TABLE IF EXISTS logs;
|
|
741
697
|
CREATE TABLE logs (
|
|
742
698
|
id TEXT PRIMARY KEY,
|
|
@@ -746,1086 +702,938 @@ var LogStorage = class {
|
|
|
746
702
|
data TEXT
|
|
747
703
|
)
|
|
748
704
|
`);
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Stores a new log entry in the database.
|
|
708
|
+
* Uses prepared statements for efficient and safe insertion.
|
|
709
|
+
*
|
|
710
|
+
* @param entry - The log entry to store
|
|
711
|
+
* @example
|
|
712
|
+
* storage.store({
|
|
713
|
+
* id: "abc123",
|
|
714
|
+
* timestamp: Date.now(),
|
|
715
|
+
* level: "info",
|
|
716
|
+
* message: "User logged in",
|
|
717
|
+
* data: JSON.stringify({ userId: 123 })
|
|
718
|
+
* });
|
|
719
|
+
*/
|
|
720
|
+
store(entry) {
|
|
721
|
+
this.db.prepare(`
|
|
766
722
|
INSERT INTO logs (id, timestamp, level, message, data)
|
|
767
723
|
VALUES (?, ?, ?, ?, ?)
|
|
768
724
|
`).run(entry.id, entry.timestamp, entry.level, entry.message, entry.data);
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Retrieves all logs from the database in chronological order.
|
|
728
|
+
* Used when displaying the full log history or clearing filters.
|
|
729
|
+
*
|
|
730
|
+
* @returns Array of log entries sorted by timestamp
|
|
731
|
+
*/
|
|
732
|
+
getAllLogs() {
|
|
733
|
+
return this.db.prepare("SELECT * FROM logs ORDER BY timestamp ASC").all();
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Searches logs based on a text query.
|
|
737
|
+
* Performs a case-insensitive search across multiple fields:
|
|
738
|
+
* - Log ID
|
|
739
|
+
* - Message content
|
|
740
|
+
* - Structured data
|
|
741
|
+
*
|
|
742
|
+
* @param searchText - Text to search for
|
|
743
|
+
* @returns Array of matching log entries sorted by timestamp
|
|
744
|
+
* @example
|
|
745
|
+
* const errorLogs = storage.searchLogs("error");
|
|
746
|
+
* const userLogs = storage.searchLogs("userId:123");
|
|
747
|
+
*/
|
|
748
|
+
searchLogs(searchText) {
|
|
749
|
+
const query = `
|
|
794
750
|
SELECT * FROM logs
|
|
795
751
|
WHERE id LIKE ?
|
|
796
752
|
OR message LIKE ?
|
|
797
753
|
OR data LIKE ?
|
|
798
754
|
ORDER BY timestamp ASC
|
|
799
755
|
`;
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const query = `
|
|
756
|
+
const pattern = `%${searchText}%`;
|
|
757
|
+
return this.db.prepare(query).all(pattern, pattern, pattern);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Gets the total number of logs in the database.
|
|
761
|
+
* Uses an efficient COUNT query instead of loading all logs.
|
|
762
|
+
*
|
|
763
|
+
* @returns Total number of log entries
|
|
764
|
+
*/
|
|
765
|
+
getLogCount() {
|
|
766
|
+
return this.db.prepare("SELECT COUNT(*) as count FROM logs").get().count;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Gets the total number of logs matching a search query.
|
|
770
|
+
* Uses an efficient COUNT query instead of loading all logs.
|
|
771
|
+
*
|
|
772
|
+
* @param searchText - Text to search for
|
|
773
|
+
* @returns Number of matching log entries
|
|
774
|
+
*/
|
|
775
|
+
getFilteredLogCount(searchText) {
|
|
776
|
+
const query = `
|
|
822
777
|
SELECT COUNT(*) as count FROM logs
|
|
823
778
|
WHERE id LIKE ?
|
|
824
779
|
OR message LIKE ?
|
|
825
780
|
OR data LIKE ?
|
|
826
781
|
`;
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
}
|
|
782
|
+
const pattern = `%${searchText}%`;
|
|
783
|
+
return this.db.prepare(query).get(pattern, pattern, pattern).count;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Closes the database connection and performs cleanup.
|
|
787
|
+
* Should be called when the application exits or the transport is destroyed.
|
|
788
|
+
*/
|
|
789
|
+
close() {
|
|
790
|
+
this.db.close();
|
|
791
|
+
}
|
|
838
792
|
};
|
|
839
793
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
794
|
+
//#endregion
|
|
795
|
+
//#region src/themes.ts
|
|
796
|
+
/**
|
|
797
|
+
* Moonlight - A dark theme with cool blue tones
|
|
798
|
+
* Inspired by moonlit nights and modern IDEs
|
|
799
|
+
*
|
|
800
|
+
* Color Palette:
|
|
801
|
+
* - Primary: Cool blues and soft greens
|
|
802
|
+
* - Accents: Warm yellows and soft reds
|
|
803
|
+
* - Background: Assumes dark terminal (black or very dark grey)
|
|
804
|
+
*
|
|
805
|
+
* Best used with:
|
|
806
|
+
* - Dark terminal themes
|
|
807
|
+
* - Night-time coding sessions
|
|
808
|
+
* - Environments where eye strain is a concern
|
|
809
|
+
*/
|
|
810
|
+
const moonlight = {
|
|
811
|
+
simpleView: {
|
|
812
|
+
colors: {
|
|
813
|
+
trace: chalk$1.rgb(114, 135, 153),
|
|
814
|
+
debug: chalk$1.rgb(130, 170, 255),
|
|
815
|
+
info: chalk$1.rgb(195, 232, 141),
|
|
816
|
+
warn: chalk$1.rgb(255, 203, 107),
|
|
817
|
+
error: chalk$1.rgb(247, 118, 142),
|
|
818
|
+
fatal: chalk$1.bgRgb(247, 118, 142).white
|
|
819
|
+
},
|
|
820
|
+
logIdColor: chalk$1.rgb(84, 98, 117),
|
|
821
|
+
dataValueColor: chalk$1.rgb(209, 219, 231),
|
|
822
|
+
dataKeyColor: chalk$1.rgb(130, 170, 255),
|
|
823
|
+
selectorColor: chalk$1.rgb(137, 221, 255)
|
|
824
|
+
},
|
|
825
|
+
detailedView: {
|
|
826
|
+
colors: {
|
|
827
|
+
trace: chalk$1.rgb(114, 135, 153),
|
|
828
|
+
debug: chalk$1.rgb(130, 170, 255),
|
|
829
|
+
info: chalk$1.rgb(195, 232, 141),
|
|
830
|
+
warn: chalk$1.rgb(255, 203, 107),
|
|
831
|
+
error: chalk$1.rgb(247, 118, 142),
|
|
832
|
+
fatal: chalk$1.bgRgb(247, 118, 142).white
|
|
833
|
+
},
|
|
834
|
+
logIdColor: chalk$1.rgb(84, 98, 117),
|
|
835
|
+
dataValueColor: chalk$1.rgb(209, 219, 231),
|
|
836
|
+
dataKeyColor: chalk$1.rgb(130, 170, 255),
|
|
837
|
+
selectorColor: chalk$1.rgb(137, 221, 255),
|
|
838
|
+
headerColor: chalk$1.rgb(137, 221, 255),
|
|
839
|
+
labelColor: chalk$1.rgb(137, 221, 255).bold,
|
|
840
|
+
separatorColor: chalk$1.rgb(84, 98, 117),
|
|
841
|
+
jsonColors: {
|
|
842
|
+
keysColor: chalk$1.rgb(130, 170, 255),
|
|
843
|
+
dashColor: chalk$1.rgb(209, 219, 231),
|
|
844
|
+
numberColor: chalk$1.rgb(247, 140, 108),
|
|
845
|
+
stringColor: chalk$1.rgb(195, 232, 141),
|
|
846
|
+
multilineStringColor: chalk$1.rgb(195, 232, 141),
|
|
847
|
+
positiveNumberColor: chalk$1.rgb(195, 232, 141),
|
|
848
|
+
negativeNumberColor: chalk$1.rgb(247, 118, 142),
|
|
849
|
+
booleanColor: chalk$1.rgb(255, 203, 107),
|
|
850
|
+
nullUndefinedColor: chalk$1.rgb(114, 135, 153),
|
|
851
|
+
dateColor: chalk$1.rgb(199, 146, 234)
|
|
852
|
+
}
|
|
853
|
+
}
|
|
897
854
|
};
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
855
|
+
/**
|
|
856
|
+
* Sunlight - A light theme with warm tones
|
|
857
|
+
* Inspired by daylight reading and paper documentation
|
|
858
|
+
*
|
|
859
|
+
* Color Palette:
|
|
860
|
+
* - Primary: Deep, rich colors that contrast well with white
|
|
861
|
+
* - Accents: Earth tones and deep jewel tones
|
|
862
|
+
* - Background: Assumes light terminal (white or very light grey)
|
|
863
|
+
*
|
|
864
|
+
* Best used with:
|
|
865
|
+
* - Light terminal themes
|
|
866
|
+
* - Daytime coding sessions
|
|
867
|
+
* - High-glare environments
|
|
868
|
+
* - Printed documentation
|
|
869
|
+
*/
|
|
870
|
+
const sunlight = {
|
|
871
|
+
simpleView: {
|
|
872
|
+
colors: {
|
|
873
|
+
trace: chalk$1.rgb(110, 110, 110),
|
|
874
|
+
debug: chalk$1.rgb(32, 96, 159),
|
|
875
|
+
info: chalk$1.rgb(35, 134, 54),
|
|
876
|
+
warn: chalk$1.rgb(176, 95, 0),
|
|
877
|
+
error: chalk$1.rgb(191, 0, 0),
|
|
878
|
+
fatal: chalk$1.bgRgb(191, 0, 0).white
|
|
879
|
+
},
|
|
880
|
+
logIdColor: chalk$1.rgb(110, 110, 110),
|
|
881
|
+
dataValueColor: chalk$1.rgb(0, 0, 0),
|
|
882
|
+
dataKeyColor: chalk$1.rgb(32, 96, 159),
|
|
883
|
+
selectorColor: chalk$1.rgb(0, 91, 129)
|
|
884
|
+
},
|
|
885
|
+
detailedView: {
|
|
886
|
+
colors: {
|
|
887
|
+
trace: chalk$1.rgb(110, 110, 110),
|
|
888
|
+
debug: chalk$1.rgb(32, 96, 159),
|
|
889
|
+
info: chalk$1.rgb(35, 134, 54),
|
|
890
|
+
warn: chalk$1.rgb(176, 95, 0),
|
|
891
|
+
error: chalk$1.rgb(191, 0, 0),
|
|
892
|
+
fatal: chalk$1.bgRgb(191, 0, 0).white
|
|
893
|
+
},
|
|
894
|
+
logIdColor: chalk$1.rgb(110, 110, 110),
|
|
895
|
+
dataValueColor: chalk$1.rgb(0, 0, 0),
|
|
896
|
+
dataKeyColor: chalk$1.rgb(32, 96, 159),
|
|
897
|
+
selectorColor: chalk$1.rgb(0, 91, 129),
|
|
898
|
+
headerColor: chalk$1.rgb(0, 91, 129),
|
|
899
|
+
labelColor: chalk$1.rgb(0, 91, 129).bold,
|
|
900
|
+
separatorColor: chalk$1.rgb(110, 110, 110),
|
|
901
|
+
jsonColors: {
|
|
902
|
+
keysColor: chalk$1.rgb(32, 96, 159),
|
|
903
|
+
dashColor: chalk$1.rgb(0, 0, 0),
|
|
904
|
+
numberColor: chalk$1.rgb(170, 55, 49),
|
|
905
|
+
stringColor: chalk$1.rgb(35, 134, 54),
|
|
906
|
+
multilineStringColor: chalk$1.rgb(35, 134, 54),
|
|
907
|
+
positiveNumberColor: chalk$1.rgb(46, 125, 50),
|
|
908
|
+
negativeNumberColor: chalk$1.rgb(183, 28, 28),
|
|
909
|
+
booleanColor: chalk$1.rgb(176, 95, 0),
|
|
910
|
+
nullUndefinedColor: chalk$1.rgb(110, 110, 110),
|
|
911
|
+
dateColor: chalk$1.rgb(123, 31, 162)
|
|
912
|
+
}
|
|
913
|
+
}
|
|
950
914
|
};
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
915
|
+
/**
|
|
916
|
+
* Neon - A dark theme with vibrant cyberpunk colors
|
|
917
|
+
* Inspired by neon-lit cityscapes and retro-futuristic aesthetics
|
|
918
|
+
*
|
|
919
|
+
* Color Palette:
|
|
920
|
+
* - Primary: Electric blues and hot pinks
|
|
921
|
+
* - Accents: Bright purples and cyber greens
|
|
922
|
+
* - Background: Assumes dark terminal (black or very dark grey)
|
|
923
|
+
*
|
|
924
|
+
* Best used with:
|
|
925
|
+
* - Dark terminal themes
|
|
926
|
+
* - High-contrast preferences
|
|
927
|
+
* - Modern, tech-focused applications
|
|
928
|
+
*/
|
|
929
|
+
const neon = {
|
|
930
|
+
simpleView: {
|
|
931
|
+
colors: {
|
|
932
|
+
trace: chalk$1.rgb(108, 108, 255),
|
|
933
|
+
debug: chalk$1.rgb(255, 82, 246),
|
|
934
|
+
info: chalk$1.rgb(0, 255, 163),
|
|
935
|
+
warn: chalk$1.rgb(255, 231, 46),
|
|
936
|
+
error: chalk$1.rgb(255, 53, 91),
|
|
937
|
+
fatal: chalk$1.bgRgb(255, 53, 91).rgb(0, 255, 163)
|
|
938
|
+
},
|
|
939
|
+
logIdColor: chalk$1.rgb(187, 134, 252),
|
|
940
|
+
dataValueColor: chalk$1.rgb(255, 255, 255),
|
|
941
|
+
dataKeyColor: chalk$1.rgb(0, 255, 240),
|
|
942
|
+
selectorColor: chalk$1.rgb(0, 255, 240)
|
|
943
|
+
},
|
|
944
|
+
detailedView: {
|
|
945
|
+
colors: {
|
|
946
|
+
trace: chalk$1.rgb(108, 108, 255),
|
|
947
|
+
debug: chalk$1.rgb(255, 82, 246),
|
|
948
|
+
info: chalk$1.rgb(0, 255, 163),
|
|
949
|
+
warn: chalk$1.rgb(255, 231, 46),
|
|
950
|
+
error: chalk$1.rgb(255, 53, 91),
|
|
951
|
+
fatal: chalk$1.bgRgb(255, 53, 91).rgb(0, 255, 163)
|
|
952
|
+
},
|
|
953
|
+
logIdColor: chalk$1.rgb(187, 134, 252),
|
|
954
|
+
dataValueColor: chalk$1.rgb(255, 255, 255),
|
|
955
|
+
dataKeyColor: chalk$1.rgb(0, 255, 240),
|
|
956
|
+
selectorColor: chalk$1.rgb(0, 255, 240),
|
|
957
|
+
headerColor: chalk$1.rgb(255, 82, 246),
|
|
958
|
+
labelColor: chalk$1.rgb(255, 82, 246).bold,
|
|
959
|
+
separatorColor: chalk$1.rgb(108, 108, 255),
|
|
960
|
+
jsonColors: {
|
|
961
|
+
keysColor: chalk$1.rgb(0, 255, 240),
|
|
962
|
+
dashColor: chalk$1.rgb(255, 255, 255),
|
|
963
|
+
numberColor: chalk$1.rgb(255, 82, 246),
|
|
964
|
+
stringColor: chalk$1.rgb(0, 255, 163),
|
|
965
|
+
multilineStringColor: chalk$1.rgb(0, 255, 163),
|
|
966
|
+
positiveNumberColor: chalk$1.rgb(0, 255, 163),
|
|
967
|
+
negativeNumberColor: chalk$1.rgb(255, 53, 91),
|
|
968
|
+
booleanColor: chalk$1.rgb(255, 231, 46),
|
|
969
|
+
nullUndefinedColor: chalk$1.rgb(108, 108, 255),
|
|
970
|
+
dateColor: chalk$1.rgb(187, 134, 252)
|
|
971
|
+
}
|
|
972
|
+
}
|
|
1006
973
|
};
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
974
|
+
/**
|
|
975
|
+
* Nature - A light theme with organic, earthy colors
|
|
976
|
+
* Inspired by forest landscapes and natural elements
|
|
977
|
+
*
|
|
978
|
+
* Color Palette:
|
|
979
|
+
* - Primary: Deep forest greens and rich browns
|
|
980
|
+
* - Accents: Autumn reds and golden yellows
|
|
981
|
+
* - Background: Assumes light terminal (white or very light grey)
|
|
982
|
+
*
|
|
983
|
+
* Best used with:
|
|
984
|
+
* - Light terminal themes
|
|
985
|
+
* - Nature-inspired interfaces
|
|
986
|
+
* - Applications focusing on readability
|
|
987
|
+
*/
|
|
988
|
+
const nature = {
|
|
989
|
+
simpleView: {
|
|
990
|
+
colors: {
|
|
991
|
+
trace: chalk$1.rgb(121, 85, 72),
|
|
992
|
+
debug: chalk$1.rgb(46, 125, 50),
|
|
993
|
+
info: chalk$1.rgb(0, 105, 92),
|
|
994
|
+
warn: chalk$1.rgb(175, 115, 0),
|
|
995
|
+
error: chalk$1.rgb(183, 28, 28),
|
|
996
|
+
fatal: chalk$1.bgRgb(183, 28, 28).rgb(255, 250, 240)
|
|
997
|
+
},
|
|
998
|
+
logIdColor: chalk$1.rgb(93, 64, 55),
|
|
999
|
+
dataValueColor: chalk$1.rgb(27, 27, 27),
|
|
1000
|
+
dataKeyColor: chalk$1.rgb(56, 142, 60),
|
|
1001
|
+
selectorColor: chalk$1.rgb(0, 105, 92)
|
|
1002
|
+
},
|
|
1003
|
+
detailedView: {
|
|
1004
|
+
colors: {
|
|
1005
|
+
trace: chalk$1.rgb(121, 85, 72),
|
|
1006
|
+
debug: chalk$1.rgb(46, 125, 50),
|
|
1007
|
+
info: chalk$1.rgb(0, 105, 92),
|
|
1008
|
+
warn: chalk$1.rgb(175, 115, 0),
|
|
1009
|
+
error: chalk$1.rgb(183, 28, 28),
|
|
1010
|
+
fatal: chalk$1.bgRgb(183, 28, 28).rgb(255, 250, 240)
|
|
1011
|
+
},
|
|
1012
|
+
logIdColor: chalk$1.rgb(93, 64, 55),
|
|
1013
|
+
dataValueColor: chalk$1.rgb(27, 27, 27),
|
|
1014
|
+
dataKeyColor: chalk$1.rgb(56, 142, 60),
|
|
1015
|
+
selectorColor: chalk$1.rgb(0, 105, 92),
|
|
1016
|
+
headerColor: chalk$1.rgb(0, 77, 64),
|
|
1017
|
+
labelColor: chalk$1.rgb(0, 77, 64).bold,
|
|
1018
|
+
separatorColor: chalk$1.rgb(121, 85, 72),
|
|
1019
|
+
jsonColors: {
|
|
1020
|
+
keysColor: chalk$1.rgb(56, 142, 60),
|
|
1021
|
+
dashColor: chalk$1.rgb(27, 27, 27),
|
|
1022
|
+
numberColor: chalk$1.rgb(230, 81, 0),
|
|
1023
|
+
stringColor: chalk$1.rgb(0, 105, 92),
|
|
1024
|
+
multilineStringColor: chalk$1.rgb(0, 105, 92),
|
|
1025
|
+
positiveNumberColor: chalk$1.rgb(46, 125, 50),
|
|
1026
|
+
negativeNumberColor: chalk$1.rgb(183, 28, 28),
|
|
1027
|
+
booleanColor: chalk$1.rgb(175, 115, 0),
|
|
1028
|
+
nullUndefinedColor: chalk$1.rgb(121, 85, 72),
|
|
1029
|
+
dateColor: chalk$1.rgb(123, 31, 162)
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1062
1032
|
};
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
// Gentle lavender
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Pastel - A soft, calming theme with gentle colors
|
|
1035
|
+
* Inspired by watercolor paintings and cotton candy skies
|
|
1036
|
+
*
|
|
1037
|
+
* Color Palette:
|
|
1038
|
+
* - Primary: Soft pinks and lavenders
|
|
1039
|
+
* - Accents: Mint greens and baby blues
|
|
1040
|
+
* - Background: Assumes dark terminal (black or very dark grey)
|
|
1041
|
+
*
|
|
1042
|
+
* Best used with:
|
|
1043
|
+
* - Dark terminal themes
|
|
1044
|
+
* - Long coding sessions where eye comfort is priority
|
|
1045
|
+
* - Environments where a gentler aesthetic is preferred
|
|
1046
|
+
* - Applications focusing on reduced visual stress
|
|
1047
|
+
*/
|
|
1048
|
+
const pastel = {
|
|
1049
|
+
simpleView: {
|
|
1050
|
+
colors: {
|
|
1051
|
+
trace: chalk$1.rgb(179, 189, 203),
|
|
1052
|
+
debug: chalk$1.rgb(189, 178, 255),
|
|
1053
|
+
info: chalk$1.rgb(170, 236, 205),
|
|
1054
|
+
warn: chalk$1.rgb(255, 223, 186),
|
|
1055
|
+
error: chalk$1.rgb(255, 188, 188),
|
|
1056
|
+
fatal: chalk$1.bgRgb(255, 188, 188).rgb(76, 40, 40)
|
|
1057
|
+
},
|
|
1058
|
+
logIdColor: chalk$1.rgb(203, 195, 227),
|
|
1059
|
+
dataValueColor: chalk$1.rgb(236, 236, 236),
|
|
1060
|
+
dataKeyColor: chalk$1.rgb(186, 207, 255),
|
|
1061
|
+
selectorColor: chalk$1.rgb(189, 178, 255)
|
|
1062
|
+
},
|
|
1063
|
+
detailedView: {
|
|
1064
|
+
colors: {
|
|
1065
|
+
trace: chalk$1.rgb(179, 189, 203),
|
|
1066
|
+
debug: chalk$1.rgb(189, 178, 255),
|
|
1067
|
+
info: chalk$1.rgb(170, 236, 205),
|
|
1068
|
+
warn: chalk$1.rgb(255, 223, 186),
|
|
1069
|
+
error: chalk$1.rgb(255, 188, 188),
|
|
1070
|
+
fatal: chalk$1.bgRgb(255, 188, 188).rgb(76, 40, 40)
|
|
1071
|
+
},
|
|
1072
|
+
logIdColor: chalk$1.rgb(203, 195, 227),
|
|
1073
|
+
dataValueColor: chalk$1.rgb(236, 236, 236),
|
|
1074
|
+
dataKeyColor: chalk$1.rgb(186, 207, 255),
|
|
1075
|
+
selectorColor: chalk$1.rgb(189, 178, 255),
|
|
1076
|
+
headerColor: chalk$1.rgb(255, 198, 255),
|
|
1077
|
+
labelColor: chalk$1.rgb(255, 198, 255).bold,
|
|
1078
|
+
separatorColor: chalk$1.rgb(179, 189, 203),
|
|
1079
|
+
jsonColors: {
|
|
1080
|
+
keysColor: chalk$1.rgb(186, 207, 255),
|
|
1081
|
+
dashColor: chalk$1.rgb(236, 236, 236),
|
|
1082
|
+
numberColor: chalk$1.rgb(255, 198, 255),
|
|
1083
|
+
stringColor: chalk$1.rgb(170, 236, 205),
|
|
1084
|
+
multilineStringColor: chalk$1.rgb(170, 236, 205),
|
|
1085
|
+
positiveNumberColor: chalk$1.rgb(170, 236, 205),
|
|
1086
|
+
negativeNumberColor: chalk$1.rgb(255, 188, 188),
|
|
1087
|
+
booleanColor: chalk$1.rgb(255, 223, 186),
|
|
1088
|
+
nullUndefinedColor: chalk$1.rgb(179, 189, 203),
|
|
1089
|
+
dateColor: chalk$1.rgb(189, 178, 255)
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1125
1092
|
};
|
|
1126
1093
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1094
|
+
//#endregion
|
|
1095
|
+
//#region src/UIManager.ts
|
|
1096
|
+
/**
|
|
1097
|
+
* Manages UI state and user interaction.
|
|
1098
|
+
* Acts as the controller between the storage and rendering layers.
|
|
1099
|
+
* Handles all keyboard input and view transitions.
|
|
1100
|
+
*/
|
|
1130
1101
|
var UIManager = class {
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
break;
|
|
1508
|
-
}
|
|
1509
|
-
case "left": {
|
|
1510
|
-
if (this.selectedIndex > 0) {
|
|
1511
|
-
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
1512
|
-
const entry = this.logs[this.selectedIndex];
|
|
1513
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1514
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1515
|
-
this.renderer.renderDetailView(
|
|
1516
|
-
entry,
|
|
1517
|
-
prevEntry,
|
|
1518
|
-
nextEntry,
|
|
1519
|
-
0,
|
|
1520
|
-
this.selectedIndex + 1,
|
|
1521
|
-
this.logs.length,
|
|
1522
|
-
this.filterText
|
|
1523
|
-
);
|
|
1524
|
-
}
|
|
1525
|
-
break;
|
|
1526
|
-
}
|
|
1527
|
-
case "right": {
|
|
1528
|
-
if (this.selectedIndex < this.logs.length - 1) {
|
|
1529
|
-
this.selectedIndex = Math.min(this.logs.length - 1, this.selectedIndex + 1);
|
|
1530
|
-
const entry = this.logs[this.selectedIndex];
|
|
1531
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1532
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1533
|
-
this.renderer.renderDetailView(
|
|
1534
|
-
entry,
|
|
1535
|
-
prevEntry,
|
|
1536
|
-
nextEntry,
|
|
1537
|
-
0,
|
|
1538
|
-
this.selectedIndex + 1,
|
|
1539
|
-
this.logs.length,
|
|
1540
|
-
this.filterText
|
|
1541
|
-
);
|
|
1542
|
-
}
|
|
1543
|
-
break;
|
|
1544
|
-
}
|
|
1545
|
-
case "tab": {
|
|
1546
|
-
if (this.renderer.isInJsonView()) {
|
|
1547
|
-
this.renderer.toggleJsonView();
|
|
1548
|
-
const entry = this.logs[this.selectedIndex];
|
|
1549
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1550
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1551
|
-
this.renderer.renderDetailView(
|
|
1552
|
-
entry,
|
|
1553
|
-
prevEntry,
|
|
1554
|
-
nextEntry,
|
|
1555
|
-
this.renderer.getDetailViewScrollPos(),
|
|
1556
|
-
this.selectedIndex + 1,
|
|
1557
|
-
this.logs.length,
|
|
1558
|
-
this.filterText
|
|
1559
|
-
);
|
|
1560
|
-
break;
|
|
1561
|
-
}
|
|
1562
|
-
this.isDetailView = false;
|
|
1563
|
-
if (this.detailViewPollInterval) {
|
|
1564
|
-
clearInterval(this.detailViewPollInterval);
|
|
1565
|
-
this.detailViewPollInterval = null;
|
|
1566
|
-
}
|
|
1567
|
-
this.isSelectionMode = true;
|
|
1568
|
-
this.updateFilteredLogs();
|
|
1569
|
-
this.renderer.renderSelectionView(
|
|
1570
|
-
this.logs,
|
|
1571
|
-
this.selectedIndex,
|
|
1572
|
-
this.filterText,
|
|
1573
|
-
this.selectionBuffer.length
|
|
1574
|
-
);
|
|
1575
|
-
break;
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
if (ch) {
|
|
1580
|
-
switch (ch.toLowerCase()) {
|
|
1581
|
-
case "w": {
|
|
1582
|
-
this.renderer.scrollDetailView(process.stdout.rows - 8);
|
|
1583
|
-
const entry = this.logs[this.selectedIndex];
|
|
1584
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1585
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1586
|
-
this.renderer.renderDetailView(
|
|
1587
|
-
entry,
|
|
1588
|
-
prevEntry,
|
|
1589
|
-
nextEntry,
|
|
1590
|
-
this.renderer.getDetailViewScrollPos(),
|
|
1591
|
-
this.selectedIndex + 1,
|
|
1592
|
-
this.logs.length
|
|
1593
|
-
);
|
|
1594
|
-
break;
|
|
1595
|
-
}
|
|
1596
|
-
case "q": {
|
|
1597
|
-
this.renderer.scrollDetailView(-process.stdout.rows + 8);
|
|
1598
|
-
const entry = this.logs[this.selectedIndex];
|
|
1599
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1600
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1601
|
-
this.renderer.renderDetailView(
|
|
1602
|
-
entry,
|
|
1603
|
-
prevEntry,
|
|
1604
|
-
nextEntry,
|
|
1605
|
-
this.renderer.getDetailViewScrollPos(),
|
|
1606
|
-
this.selectedIndex + 1,
|
|
1607
|
-
this.logs.length
|
|
1608
|
-
);
|
|
1609
|
-
break;
|
|
1610
|
-
}
|
|
1611
|
-
case "a": {
|
|
1612
|
-
if (this.selectedIndex !== 0) {
|
|
1613
|
-
this.selectedIndex = 0;
|
|
1614
|
-
const entry = this.logs[this.selectedIndex];
|
|
1615
|
-
const prevEntry = null;
|
|
1616
|
-
const nextEntry = this.logs.length > 1 ? this.logs[1] : null;
|
|
1617
|
-
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, 1, this.logs.length);
|
|
1618
|
-
}
|
|
1619
|
-
break;
|
|
1620
|
-
}
|
|
1621
|
-
case "s": {
|
|
1622
|
-
const lastIndex = this.logs.length - 1;
|
|
1623
|
-
if (this.selectedIndex !== lastIndex) {
|
|
1624
|
-
this.selectedIndex = lastIndex;
|
|
1625
|
-
const entry = this.logs[this.selectedIndex];
|
|
1626
|
-
const prevEntry = lastIndex > 0 ? this.logs[lastIndex - 1] : null;
|
|
1627
|
-
const nextEntry = null;
|
|
1628
|
-
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, this.logs.length, this.logs.length);
|
|
1629
|
-
}
|
|
1630
|
-
break;
|
|
1631
|
-
}
|
|
1632
|
-
case "c": {
|
|
1633
|
-
this.renderer.toggleArrayCollapse();
|
|
1634
|
-
const entry = this.logs[this.selectedIndex];
|
|
1635
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1636
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1637
|
-
this.renderer.renderDetailView(
|
|
1638
|
-
entry,
|
|
1639
|
-
prevEntry,
|
|
1640
|
-
nextEntry,
|
|
1641
|
-
this.renderer.getDetailViewScrollPos(),
|
|
1642
|
-
this.selectedIndex + 1,
|
|
1643
|
-
this.logs.length
|
|
1644
|
-
);
|
|
1645
|
-
break;
|
|
1646
|
-
}
|
|
1647
|
-
case "j": {
|
|
1648
|
-
this.renderer.toggleJsonView();
|
|
1649
|
-
const entry = this.logs[this.selectedIndex];
|
|
1650
|
-
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1651
|
-
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1652
|
-
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, this.selectedIndex + 1, this.logs.length);
|
|
1653
|
-
break;
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1102
|
+
/** Whether the UI is in log selection mode */
|
|
1103
|
+
isSelectionMode = false;
|
|
1104
|
+
/** Whether the UI is showing detailed log view */
|
|
1105
|
+
isDetailView = false;
|
|
1106
|
+
/** Whether log streaming is paused */
|
|
1107
|
+
isPaused = false;
|
|
1108
|
+
/** Whether interactive mode is disabled */
|
|
1109
|
+
isInteractiveDisabled;
|
|
1110
|
+
/** Buffer for logs received while paused */
|
|
1111
|
+
pauseBuffer = [];
|
|
1112
|
+
/** Buffer for new logs in selection mode */
|
|
1113
|
+
selectionBuffer = [];
|
|
1114
|
+
/** Index of currently selected log entry */
|
|
1115
|
+
selectedIndex = 0;
|
|
1116
|
+
/** Current filter text for log searching */
|
|
1117
|
+
filterText = "";
|
|
1118
|
+
/** Cached array of filtered log entries */
|
|
1119
|
+
logs = [];
|
|
1120
|
+
/** Polling interval for checking new logs in detail view */
|
|
1121
|
+
detailViewPollInterval = null;
|
|
1122
|
+
/** Polling interval for checking new logs in selection view */
|
|
1123
|
+
selectionViewPollInterval = null;
|
|
1124
|
+
/** Current terminal width in characters */
|
|
1125
|
+
termWidth = process.stdout.columns || 80;
|
|
1126
|
+
/**
|
|
1127
|
+
* Creates a new UIManager instance.
|
|
1128
|
+
* Sets up keyboard handling and cleanup handlers.
|
|
1129
|
+
*
|
|
1130
|
+
* @param renderer - Instance for handling log display
|
|
1131
|
+
* @param storage - Instance for log persistence
|
|
1132
|
+
* @param disableInteractiveMode - Whether to disable interactive mode
|
|
1133
|
+
*/
|
|
1134
|
+
constructor(renderer, storage, disableInteractiveMode = false) {
|
|
1135
|
+
this.renderer = renderer;
|
|
1136
|
+
this.storage = storage;
|
|
1137
|
+
this.isInteractiveDisabled = disableInteractiveMode;
|
|
1138
|
+
if (!this.isInteractiveDisabled) this.setupKeyboardHandling();
|
|
1139
|
+
process.stdout.on("resize", () => {
|
|
1140
|
+
this.termWidth = process.stdout.columns || 80;
|
|
1141
|
+
if (this.isDetailView) {
|
|
1142
|
+
const entry = this.logs[this.selectedIndex];
|
|
1143
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1144
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1145
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos());
|
|
1146
|
+
} else if (this.isSelectionMode) this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Sets up keyboard input handling and cleanup.
|
|
1151
|
+
* Configures raw mode for immediate key processing.
|
|
1152
|
+
* Sets up process exit handlers for cleanup.
|
|
1153
|
+
* @private
|
|
1154
|
+
*/
|
|
1155
|
+
setupKeyboardHandling() {
|
|
1156
|
+
keypress(process.stdin);
|
|
1157
|
+
process.stdin.setRawMode(true);
|
|
1158
|
+
process.stdin.on("keypress", this.handleKeypress.bind(this));
|
|
1159
|
+
const cleanup = () => {
|
|
1160
|
+
if (this.detailViewPollInterval) clearInterval(this.detailViewPollInterval);
|
|
1161
|
+
if (this.selectionViewPollInterval) clearInterval(this.selectionViewPollInterval);
|
|
1162
|
+
process.stdin.setRawMode(false);
|
|
1163
|
+
process.stdin.removeAllListeners("keypress");
|
|
1164
|
+
console.clear();
|
|
1165
|
+
this.storage.close();
|
|
1166
|
+
process.exit(0);
|
|
1167
|
+
};
|
|
1168
|
+
process.on("SIGINT", cleanup);
|
|
1169
|
+
process.on("SIGTERM", cleanup);
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Starts polling for new logs in selection view
|
|
1173
|
+
* @private
|
|
1174
|
+
*/
|
|
1175
|
+
startSelectionViewPolling() {
|
|
1176
|
+
if (this.selectionViewPollInterval) clearInterval(this.selectionViewPollInterval);
|
|
1177
|
+
this.selectionViewPollInterval = setInterval(() => {
|
|
1178
|
+
if (!this.isSelectionMode) {
|
|
1179
|
+
clearInterval(this.selectionViewPollInterval);
|
|
1180
|
+
this.selectionViewPollInterval = null;
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
if (this.selectionBuffer.length > 0) this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1184
|
+
}, 2e3);
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Starts polling for new logs in detail view
|
|
1188
|
+
* @private
|
|
1189
|
+
*/
|
|
1190
|
+
startDetailViewPolling() {
|
|
1191
|
+
if (this.detailViewPollInterval) clearInterval(this.detailViewPollInterval);
|
|
1192
|
+
this.detailViewPollInterval = setInterval(() => {
|
|
1193
|
+
if (!this.isDetailView) {
|
|
1194
|
+
clearInterval(this.detailViewPollInterval);
|
|
1195
|
+
this.detailViewPollInterval = null;
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
const totalCount = this.filterText ? this.storage.getFilteredLogCount(this.filterText) : this.storage.getLogCount();
|
|
1199
|
+
if (totalCount !== this.logs.length) {
|
|
1200
|
+
this.logs = this.filterText ? this.storage.searchLogs(this.filterText) : this.storage.getAllLogs();
|
|
1201
|
+
const entry = this.logs[this.selectedIndex];
|
|
1202
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1203
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1204
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, totalCount, this.filterText);
|
|
1205
|
+
}
|
|
1206
|
+
}, 2e3);
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Updates the filtered list of logs based on search text.
|
|
1210
|
+
* Handles both full list and filtered views.
|
|
1211
|
+
* Maintains selection state when filter changes.
|
|
1212
|
+
* @private
|
|
1213
|
+
*/
|
|
1214
|
+
updateFilteredLogs() {
|
|
1215
|
+
if ((this.filterText ? this.storage.getFilteredLogCount(this.filterText) : this.storage.getLogCount()) - this.selectionBuffer.length !== this.logs.length) {
|
|
1216
|
+
const storedLogs = this.filterText ? this.storage.searchLogs(this.filterText) : this.storage.getAllLogs();
|
|
1217
|
+
this.logs = storedLogs.slice(0, storedLogs.length - this.selectionBuffer.length);
|
|
1218
|
+
if (this.logs.length > 0) this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.logs.length - 1));
|
|
1219
|
+
else this.selectedIndex = 0;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
updateNewLogsNotification() {
|
|
1223
|
+
if (!this.isSelectionMode || !this.selectionBuffer.length) return;
|
|
1224
|
+
process.stdout.write(`\x1b[2A\r${" ".repeat(this.termWidth)}\r`);
|
|
1225
|
+
const notification = chalk$1.dim(`${this.selectionBuffer.length} new log${this.selectionBuffer.length === 1 ? "" : "s"} available (press ↓ to view)`);
|
|
1226
|
+
process.stdout.write(`${notification}\n\n`);
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Handles new log entries from the transport.
|
|
1230
|
+
* Stores the log and updates the display if needed.
|
|
1231
|
+
*
|
|
1232
|
+
* @param entry - New log entry to process
|
|
1233
|
+
*/
|
|
1234
|
+
handleNewLog(entry) {
|
|
1235
|
+
this.storage.store(entry);
|
|
1236
|
+
if (this.isInteractiveDisabled) {
|
|
1237
|
+
this.renderer.renderLogLine(entry);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
if (this.isSelectionMode) {
|
|
1241
|
+
this.selectionBuffer.push(entry);
|
|
1242
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
if (!this.isDetailView) if (this.isPaused) {
|
|
1246
|
+
this.pauseBuffer.push(entry);
|
|
1247
|
+
process.stdout.write(`\r${chalk$1.yellow(`⏸ Paused (${this.pauseBuffer.length} new logs)`)}${" ".repeat(20)}`);
|
|
1248
|
+
} else this.renderer.renderLogLine(entry);
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Processes keyboard input and manages UI state.
|
|
1252
|
+
* Handles navigation, mode switching, and filtering.
|
|
1253
|
+
*
|
|
1254
|
+
* Key mappings:
|
|
1255
|
+
* - CTRL+C: Exit application
|
|
1256
|
+
* - TAB: Toggle selection mode
|
|
1257
|
+
* - Up/Down: Navigate logs
|
|
1258
|
+
* - Enter: View log details
|
|
1259
|
+
* - Backspace: Edit filter
|
|
1260
|
+
* - P: Toggle pause in simple view
|
|
1261
|
+
* - Other keys: Add to filter
|
|
1262
|
+
*
|
|
1263
|
+
* @param ch - Character input if available
|
|
1264
|
+
* @param key - Key event information
|
|
1265
|
+
* @private
|
|
1266
|
+
*/
|
|
1267
|
+
handleKeypress(ch, key) {
|
|
1268
|
+
if (key?.ctrl && key?.name === "c") {
|
|
1269
|
+
process.stdin.setRawMode(false);
|
|
1270
|
+
process.stdin.removeAllListeners("keypress");
|
|
1271
|
+
console.clear();
|
|
1272
|
+
this.storage.close();
|
|
1273
|
+
process.exit(0);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (!this.isSelectionMode && !this.isDetailView && ch === "p") {
|
|
1277
|
+
this.isPaused = !this.isPaused;
|
|
1278
|
+
if (!this.isPaused && this.pauseBuffer.length > 0) {
|
|
1279
|
+
process.stdout.write(`\r${" ".repeat(50)}\r`);
|
|
1280
|
+
for (const entry of this.pauseBuffer) this.renderer.renderLogLine(entry);
|
|
1281
|
+
this.pauseBuffer = [];
|
|
1282
|
+
} else if (this.isPaused) process.stdout.write(`\r${chalk$1.yellow("⏸ Paused (0 new logs)")}${" ".repeat(20)}`);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (!this.isSelectionMode && !this.isDetailView && (key?.name === "up" || key?.name === "down")) {
|
|
1286
|
+
this.isSelectionMode = true;
|
|
1287
|
+
this.filterText = "";
|
|
1288
|
+
this.isPaused = true;
|
|
1289
|
+
this.logs = this.storage.getAllLogs();
|
|
1290
|
+
this.selectedIndex = key.name === "up" ? Math.max(0, this.logs.length - 1) : Math.max(0, this.logs.length - 1);
|
|
1291
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1292
|
+
this.startSelectionViewPolling();
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
if (!this.isSelectionMode && !this.isDetailView && ch === "c") {
|
|
1296
|
+
const newMode = this.renderer.cycleViewMode();
|
|
1297
|
+
console.clear();
|
|
1298
|
+
const logs = this.storage.getAllLogs();
|
|
1299
|
+
for (const entry of logs) this.renderer.renderLogLine(entry);
|
|
1300
|
+
process.stdout.write(`\r${chalk$1.cyan(`ℹ ${{
|
|
1301
|
+
full: "Full view enabled (all data shown without truncation)",
|
|
1302
|
+
truncated: "Truncated view enabled (timestamp, ID, level, message, truncated data)",
|
|
1303
|
+
condensed: "Condensed view enabled (timestamp, level and message only)"
|
|
1304
|
+
}[newMode]}`)}${" ".repeat(20)}`);
|
|
1305
|
+
setTimeout(() => {
|
|
1306
|
+
process.stdout.write(`\r${" ".repeat(100)}\r`);
|
|
1307
|
+
}, 3e3);
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (this.isSelectionMode) {
|
|
1311
|
+
if (key) switch (key.name) {
|
|
1312
|
+
case "up":
|
|
1313
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
1314
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1315
|
+
return;
|
|
1316
|
+
case "down":
|
|
1317
|
+
if (this.selectedIndex === this.logs.length - 1 && this.selectionBuffer.length > 0) {
|
|
1318
|
+
this.logs.push(...this.selectionBuffer);
|
|
1319
|
+
this.selectionBuffer = [];
|
|
1320
|
+
}
|
|
1321
|
+
this.selectedIndex = Math.min(this.logs.length - 1, this.selectedIndex + 1);
|
|
1322
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1323
|
+
return;
|
|
1324
|
+
case "return":
|
|
1325
|
+
if (this.logs.length > 0) {
|
|
1326
|
+
this.isSelectionMode = false;
|
|
1327
|
+
this.isDetailView = true;
|
|
1328
|
+
console.clear();
|
|
1329
|
+
const selectedEntry = this.logs[this.selectedIndex];
|
|
1330
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1331
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1332
|
+
this.renderer.renderDetailView(selectedEntry, prevEntry, nextEntry, 0, this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1333
|
+
this.startDetailViewPolling();
|
|
1334
|
+
}
|
|
1335
|
+
return;
|
|
1336
|
+
case "backspace":
|
|
1337
|
+
if (this.filterText.length > 0) {
|
|
1338
|
+
this.filterText = this.filterText.slice(0, -1);
|
|
1339
|
+
this.updateFilteredLogs();
|
|
1340
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1341
|
+
}
|
|
1342
|
+
return;
|
|
1343
|
+
case "tab": {
|
|
1344
|
+
this.isSelectionMode = false;
|
|
1345
|
+
this.isPaused = false;
|
|
1346
|
+
if (this.selectionViewPollInterval) {
|
|
1347
|
+
clearInterval(this.selectionViewPollInterval);
|
|
1348
|
+
this.selectionViewPollInterval = null;
|
|
1349
|
+
}
|
|
1350
|
+
this.filterText = "";
|
|
1351
|
+
console.clear();
|
|
1352
|
+
const logs = this.storage.getAllLogs();
|
|
1353
|
+
for (const entry of logs) this.renderer.renderLogLine(entry);
|
|
1354
|
+
if (this.selectionBuffer.length > 0) {
|
|
1355
|
+
for (const entry of this.selectionBuffer) this.renderer.renderLogLine(entry);
|
|
1356
|
+
this.selectionBuffer = [];
|
|
1357
|
+
}
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (ch && (!key || !key.ctrl && !key.meta) && ch.length === 1) {
|
|
1362
|
+
this.filterText += ch;
|
|
1363
|
+
this.updateFilteredLogs();
|
|
1364
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (this.isDetailView) {
|
|
1369
|
+
if (key?.name) switch (key.name) {
|
|
1370
|
+
case "up": {
|
|
1371
|
+
this.renderer.scrollDetailView(-1);
|
|
1372
|
+
const entry = this.logs[this.selectedIndex];
|
|
1373
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1374
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1375
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1376
|
+
break;
|
|
1377
|
+
}
|
|
1378
|
+
case "down": {
|
|
1379
|
+
this.renderer.scrollDetailView(1);
|
|
1380
|
+
const entry = this.logs[this.selectedIndex];
|
|
1381
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1382
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1383
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1384
|
+
break;
|
|
1385
|
+
}
|
|
1386
|
+
case "left":
|
|
1387
|
+
if (this.selectedIndex > 0) {
|
|
1388
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
1389
|
+
const entry = this.logs[this.selectedIndex];
|
|
1390
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1391
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1392
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1393
|
+
}
|
|
1394
|
+
break;
|
|
1395
|
+
case "right":
|
|
1396
|
+
if (this.selectedIndex < this.logs.length - 1) {
|
|
1397
|
+
this.selectedIndex = Math.min(this.logs.length - 1, this.selectedIndex + 1);
|
|
1398
|
+
const entry = this.logs[this.selectedIndex];
|
|
1399
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1400
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1401
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1402
|
+
}
|
|
1403
|
+
break;
|
|
1404
|
+
case "tab":
|
|
1405
|
+
if (this.renderer.isInJsonView()) {
|
|
1406
|
+
this.renderer.toggleJsonView();
|
|
1407
|
+
const entry = this.logs[this.selectedIndex];
|
|
1408
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1409
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1410
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length, this.filterText);
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
this.isDetailView = false;
|
|
1414
|
+
if (this.detailViewPollInterval) {
|
|
1415
|
+
clearInterval(this.detailViewPollInterval);
|
|
1416
|
+
this.detailViewPollInterval = null;
|
|
1417
|
+
}
|
|
1418
|
+
this.isSelectionMode = true;
|
|
1419
|
+
this.updateFilteredLogs();
|
|
1420
|
+
this.renderer.renderSelectionView(this.logs, this.selectedIndex, this.filterText, this.selectionBuffer.length);
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1423
|
+
if (ch) switch (ch.toLowerCase()) {
|
|
1424
|
+
case "w": {
|
|
1425
|
+
this.renderer.scrollDetailView(process.stdout.rows - 8);
|
|
1426
|
+
const entry = this.logs[this.selectedIndex];
|
|
1427
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1428
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1429
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length);
|
|
1430
|
+
break;
|
|
1431
|
+
}
|
|
1432
|
+
case "q": {
|
|
1433
|
+
this.renderer.scrollDetailView(-process.stdout.rows + 8);
|
|
1434
|
+
const entry = this.logs[this.selectedIndex];
|
|
1435
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1436
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1437
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length);
|
|
1438
|
+
break;
|
|
1439
|
+
}
|
|
1440
|
+
case "a":
|
|
1441
|
+
if (this.selectedIndex !== 0) {
|
|
1442
|
+
this.selectedIndex = 0;
|
|
1443
|
+
const entry = this.logs[this.selectedIndex];
|
|
1444
|
+
const prevEntry = null;
|
|
1445
|
+
const nextEntry = this.logs.length > 1 ? this.logs[1] : null;
|
|
1446
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, 1, this.logs.length);
|
|
1447
|
+
}
|
|
1448
|
+
break;
|
|
1449
|
+
case "s": {
|
|
1450
|
+
const lastIndex = this.logs.length - 1;
|
|
1451
|
+
if (this.selectedIndex !== lastIndex) {
|
|
1452
|
+
this.selectedIndex = lastIndex;
|
|
1453
|
+
const entry = this.logs[this.selectedIndex];
|
|
1454
|
+
const prevEntry = lastIndex > 0 ? this.logs[lastIndex - 1] : null;
|
|
1455
|
+
this.renderer.renderDetailView(entry, prevEntry, null, 0, this.logs.length, this.logs.length);
|
|
1456
|
+
}
|
|
1457
|
+
break;
|
|
1458
|
+
}
|
|
1459
|
+
case "c": {
|
|
1460
|
+
this.renderer.toggleArrayCollapse();
|
|
1461
|
+
const entry = this.logs[this.selectedIndex];
|
|
1462
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1463
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1464
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, this.renderer.getDetailViewScrollPos(), this.selectedIndex + 1, this.logs.length);
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
case "j": {
|
|
1468
|
+
this.renderer.toggleJsonView();
|
|
1469
|
+
const entry = this.logs[this.selectedIndex];
|
|
1470
|
+
const prevEntry = this.selectedIndex > 0 ? this.logs[this.selectedIndex - 1] : null;
|
|
1471
|
+
const nextEntry = this.selectedIndex < this.logs.length - 1 ? this.logs[this.selectedIndex + 1] : null;
|
|
1472
|
+
this.renderer.renderDetailView(entry, prevEntry, nextEntry, 0, this.selectedIndex + 1, this.logs.length);
|
|
1473
|
+
break;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1659
1478
|
};
|
|
1660
1479
|
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
};
|
|
1811
|
-
this.uiManager.handleNewLog(entry);
|
|
1812
|
-
return messages;
|
|
1813
|
-
}
|
|
1480
|
+
//#endregion
|
|
1481
|
+
//#region src/PrettyTerminalTransport.ts
|
|
1482
|
+
/**
|
|
1483
|
+
* Main transport class that handles pretty terminal output and interactive features.
|
|
1484
|
+
* This class coordinates between different components:
|
|
1485
|
+
* - LogStorage: Handles persistence of logs in SQLite
|
|
1486
|
+
* - LogRenderer: Manages all rendering and formatting
|
|
1487
|
+
* - UIManager: Handles user interaction and view state
|
|
1488
|
+
*
|
|
1489
|
+
* The transport supports two main view modes:
|
|
1490
|
+
* 1. Simple View: Real-time log output with basic formatting
|
|
1491
|
+
* 2. Interactive View: Full-screen mode with navigation and filtering
|
|
1492
|
+
*
|
|
1493
|
+
* Usage:
|
|
1494
|
+
* ```typescript
|
|
1495
|
+
* const transport = PrettyTerminalTransport.getInstance({
|
|
1496
|
+
* maxInlineDepth: 4,
|
|
1497
|
+
* maxInlineLength: 120,
|
|
1498
|
+
* theme: customTheme
|
|
1499
|
+
* });
|
|
1500
|
+
* ```
|
|
1501
|
+
*/
|
|
1502
|
+
var PrettyTerminalTransport = class PrettyTerminalTransport extends LoggerlessTransport {
|
|
1503
|
+
/** Singleton instance of the transport */
|
|
1504
|
+
static instance = null;
|
|
1505
|
+
/** Handles all rendering and formatting of logs */
|
|
1506
|
+
renderer;
|
|
1507
|
+
/** Manages log persistence in SQLite database */
|
|
1508
|
+
storage;
|
|
1509
|
+
/** Manages user interaction and view state */
|
|
1510
|
+
uiManager;
|
|
1511
|
+
/** Configuration options */
|
|
1512
|
+
config;
|
|
1513
|
+
/**
|
|
1514
|
+
* Creates a new PrettyTerminalTransport instance.
|
|
1515
|
+
* This is a singleton class - only one instance can exist at a time.
|
|
1516
|
+
* Use getInstance() instead of constructor directly.
|
|
1517
|
+
*
|
|
1518
|
+
* @param config - Configuration options for the transport
|
|
1519
|
+
* @throws Error if attempting to create multiple instances
|
|
1520
|
+
*/
|
|
1521
|
+
constructor(config = {}) {
|
|
1522
|
+
if (PrettyTerminalTransport.instance) throw new Error("PrettyTerminalTransport is a singleton. Use getPrettyTerminal() instead.");
|
|
1523
|
+
super(config);
|
|
1524
|
+
this.config = config;
|
|
1525
|
+
if (config.enabled === false) return;
|
|
1526
|
+
const maxInlineDepth = config.maxInlineDepth || 4;
|
|
1527
|
+
const maxInlineLength = config.maxInlineLength || 120;
|
|
1528
|
+
const theme = config.theme || moonlight;
|
|
1529
|
+
const logFile = config.logFile;
|
|
1530
|
+
const simpleViewConfig = {
|
|
1531
|
+
colors: {
|
|
1532
|
+
trace: chalk$1.gray,
|
|
1533
|
+
debug: chalk$1.blue,
|
|
1534
|
+
info: chalk$1.green,
|
|
1535
|
+
warn: chalk$1.yellow,
|
|
1536
|
+
error: chalk$1.red,
|
|
1537
|
+
fatal: chalk$1.bgRed.white,
|
|
1538
|
+
...theme.simpleView.colors
|
|
1539
|
+
},
|
|
1540
|
+
logIdColor: theme.simpleView.logIdColor || chalk$1.dim,
|
|
1541
|
+
dataValueColor: theme.simpleView.dataValueColor || chalk$1.white,
|
|
1542
|
+
dataKeyColor: theme.simpleView.dataKeyColor || chalk$1.dim,
|
|
1543
|
+
selectorColor: theme.simpleView.selectorColor || chalk$1.cyan
|
|
1544
|
+
};
|
|
1545
|
+
const detailedViewConfig = {
|
|
1546
|
+
colors: {
|
|
1547
|
+
trace: chalk$1.gray,
|
|
1548
|
+
debug: chalk$1.blue,
|
|
1549
|
+
info: chalk$1.green,
|
|
1550
|
+
warn: chalk$1.yellow,
|
|
1551
|
+
error: chalk$1.red,
|
|
1552
|
+
fatal: chalk$1.bgRed.white,
|
|
1553
|
+
...theme.detailedView?.colors
|
|
1554
|
+
},
|
|
1555
|
+
logIdColor: theme.detailedView?.logIdColor || chalk$1.dim,
|
|
1556
|
+
dataValueColor: theme.detailedView?.dataValueColor || chalk$1.white,
|
|
1557
|
+
dataKeyColor: theme.detailedView?.dataKeyColor || chalk$1.dim,
|
|
1558
|
+
selectorColor: theme.detailedView?.selectorColor || chalk$1.cyan,
|
|
1559
|
+
headerColor: theme.detailedView?.headerColor || chalk$1.cyan,
|
|
1560
|
+
labelColor: theme.detailedView?.labelColor || chalk$1.cyan.bold,
|
|
1561
|
+
separatorColor: theme.detailedView?.separatorColor || chalk$1.dim,
|
|
1562
|
+
jsonColors: {
|
|
1563
|
+
keysColor: chalk$1.yellow,
|
|
1564
|
+
dashColor: chalk$1.white,
|
|
1565
|
+
numberColor: chalk$1.yellow,
|
|
1566
|
+
stringColor: chalk$1.white,
|
|
1567
|
+
multilineStringColor: chalk$1.white,
|
|
1568
|
+
positiveNumberColor: chalk$1.green,
|
|
1569
|
+
negativeNumberColor: chalk$1.red,
|
|
1570
|
+
booleanColor: chalk$1.cyan,
|
|
1571
|
+
nullUndefinedColor: chalk$1.grey,
|
|
1572
|
+
dateColor: chalk$1.magenta,
|
|
1573
|
+
...theme.detailedView?.jsonColors
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
this.storage = new LogStorage(logFile);
|
|
1577
|
+
this.renderer = new LogRenderer(simpleViewConfig, detailedViewConfig, maxInlineDepth, maxInlineLength);
|
|
1578
|
+
this.uiManager = new UIManager(this.renderer, this.storage, config.disableInteractiveMode);
|
|
1579
|
+
PrettyTerminalTransport.instance = this;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Gets or creates the singleton instance of PrettyTerminalTransport.
|
|
1583
|
+
* This is the recommended way to obtain a transport instance.
|
|
1584
|
+
*
|
|
1585
|
+
* @param config - Configuration options for the transport
|
|
1586
|
+
* @returns The singleton instance of PrettyTerminalTransport
|
|
1587
|
+
*/
|
|
1588
|
+
static getInstance(config = {}) {
|
|
1589
|
+
if (!PrettyTerminalTransport.instance) PrettyTerminalTransport.instance = new PrettyTerminalTransport(config);
|
|
1590
|
+
return PrettyTerminalTransport.instance;
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Generates a random ID for each log entry.
|
|
1594
|
+
* Uses base36 encoding for compact, readable IDs.
|
|
1595
|
+
*
|
|
1596
|
+
* @returns A 6-character string ID
|
|
1597
|
+
* @example
|
|
1598
|
+
* "a1b2c3" // Example generated ID
|
|
1599
|
+
*/
|
|
1600
|
+
generateId() {
|
|
1601
|
+
return Math.random().toString(36).substring(2, 8);
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Main transport method that receives logs from LogLayer.
|
|
1605
|
+
* This method is called for each log event and handles:
|
|
1606
|
+
* - Generating a unique ID for the log
|
|
1607
|
+
* - Converting the log data to a storable format
|
|
1608
|
+
* - Storing the log in the database
|
|
1609
|
+
* - Rendering the log if not in selection mode
|
|
1610
|
+
*
|
|
1611
|
+
* @param logLevel - The severity level of the log
|
|
1612
|
+
* @param messages - Array of message strings to be joined
|
|
1613
|
+
* @param data - Additional structured data to be logged
|
|
1614
|
+
* @param hasData - Whether the log includes additional data
|
|
1615
|
+
* @returns The original messages array
|
|
1616
|
+
*/
|
|
1617
|
+
shipToLogger({ logLevel, messages, data, hasData }) {
|
|
1618
|
+
if (this.config.enabled === false) return messages;
|
|
1619
|
+
const entry = {
|
|
1620
|
+
id: this.generateId(),
|
|
1621
|
+
timestamp: Date.now(),
|
|
1622
|
+
level: logLevel,
|
|
1623
|
+
message: messages.join(" "),
|
|
1624
|
+
data: hasData ? JSON.stringify(data) : null
|
|
1625
|
+
};
|
|
1626
|
+
this.uiManager.handleNewLog(entry);
|
|
1627
|
+
return messages;
|
|
1628
|
+
}
|
|
1814
1629
|
};
|
|
1815
1630
|
|
|
1816
|
-
|
|
1817
|
-
|
|
1631
|
+
//#endregion
|
|
1632
|
+
//#region src/index.ts
|
|
1818
1633
|
function getPrettyTerminal(config = {}) {
|
|
1819
|
-
|
|
1634
|
+
return PrettyTerminalTransport.getInstance(config);
|
|
1820
1635
|
}
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
getPrettyTerminal,
|
|
1825
|
-
moonlight,
|
|
1826
|
-
nature,
|
|
1827
|
-
neon,
|
|
1828
|
-
pastel,
|
|
1829
|
-
sunlight
|
|
1830
|
-
};
|
|
1636
|
+
|
|
1637
|
+
//#endregion
|
|
1638
|
+
export { PrettyTerminalTransport, chalk, getPrettyTerminal, moonlight, nature, neon, pastel, sunlight };
|
|
1831
1639
|
//# sourceMappingURL=index.js.map
|