kailogger 1.0.0-dark.red → 1.0.2
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/README.md +195 -53
- package/dist/core/Config.d.ts +15 -0
- package/dist/core/Config.js +44 -0
- package/dist/core/Logger.d.ts +75 -4
- package/dist/core/Logger.js +375 -47
- package/dist/core/Scope.d.ts +13 -0
- package/dist/core/Scope.js +36 -0
- package/dist/features/Chart.d.ts +15 -0
- package/dist/features/Chart.js +64 -0
- package/dist/features/Diff.d.ts +3 -0
- package/dist/features/Diff.js +30 -0
- package/dist/features/Encrypt.d.ts +10 -0
- package/dist/features/Encrypt.js +47 -0
- package/dist/features/Notify.d.ts +14 -0
- package/dist/features/Notify.js +70 -0
- package/dist/features/Screenshot.d.ts +10 -0
- package/dist/features/Screenshot.js +106 -0
- package/dist/features/Sound.d.ts +12 -0
- package/dist/features/Sound.js +116 -0
- package/dist/features/Timer.d.ts +6 -0
- package/dist/features/Timer.js +38 -0
- package/dist/features/Tree.d.ts +7 -0
- package/dist/features/Tree.js +25 -0
- package/dist/features/index.d.ts +8 -0
- package/dist/features/index.js +24 -0
- package/dist/icon/logo.png +0 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.js +21 -1
- package/dist/sounds/error.wav +0 -0
- package/dist/sounds/notification.wav +0 -0
- package/dist/sounds/success.wav +0 -0
- package/dist/sounds/warning.wav +0 -0
- package/dist/styles/KaiChroma.d.ts +85 -0
- package/dist/styles/KaiChroma.js +407 -0
- package/dist/styles/gradients.d.ts +28 -0
- package/dist/styles/palettes.d.ts +21 -26
- package/dist/styles/palettes.js +167 -13
- package/dist/transports/ConsoleTransport.d.ts +9 -0
- package/dist/transports/ConsoleTransport.js +18 -0
- package/dist/transports/FileTransport.d.ts +16 -0
- package/dist/transports/FileTransport.js +84 -0
- package/dist/transports/WebhookTransport.d.ts +15 -0
- package/dist/transports/WebhookTransport.js +31 -0
- package/dist/transports/index.d.ts +3 -0
- package/dist/transports/index.js +19 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.js +11 -0
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.js +33 -0
- package/dist/utils/prettyError.d.ts +3 -0
- package/dist/utils/prettyError.js +94 -0
- package/dist/utils/progress.d.ts +11 -0
- package/dist/utils/progress.js +43 -0
- package/dist/utils/prompt.d.ts +4 -0
- package/dist/utils/prompt.js +59 -0
- package/dist/utils/selection.d.ts +4 -0
- package/dist/utils/selection.js +156 -0
- package/dist/utils/spinner.d.ts +1 -1
- package/dist/utils/spinner.js +9 -13
- package/dist/utils/stripAnsi.d.ts +1 -0
- package/dist/utils/stripAnsi.js +7 -0
- package/dist/utils/table.d.ts +3 -0
- package/dist/utils/table.js +35 -0
- package/examples/demo.js +134 -0
- package/examples/demo.ts +88 -25
- package/package.json +20 -6
- package/scripts/copy-assets.js +37 -0
- package/src/core/Config.ts +44 -0
- package/src/core/Logger.ts +427 -51
- package/src/core/Scope.ts +35 -0
- package/src/features/Chart.ts +81 -0
- package/src/features/Diff.ts +25 -0
- package/src/features/Encrypt.ts +47 -0
- package/src/features/Notify.ts +39 -0
- package/src/features/Screenshot.ts +70 -0
- package/src/features/Sound.ts +92 -0
- package/src/features/Timer.ts +35 -0
- package/src/features/Tree.ts +25 -0
- package/src/features/index.ts +8 -0
- package/src/icon/logo.png +0 -0
- package/src/index.ts +13 -1
- package/src/sounds/error.wav +0 -0
- package/src/sounds/notification.wav +0 -0
- package/src/sounds/success.wav +0 -0
- package/src/sounds/warning.wav +0 -0
- package/src/styles/KaiChroma.ts +370 -0
- package/src/styles/palettes.ts +197 -14
- package/src/transports/ConsoleTransport.ts +19 -0
- package/src/transports/FileTransport.ts +55 -0
- package/src/transports/WebhookTransport.ts +37 -0
- package/src/transports/index.ts +3 -0
- package/src/types/cli-highlight.d.ts +3 -0
- package/src/types/index.ts +23 -0
- package/src/utils/json.ts +33 -0
- package/src/utils/prettyError.ts +65 -0
- package/src/utils/progress.ts +56 -0
- package/src/utils/prompt.ts +27 -0
- package/src/utils/selection.ts +136 -0
- package/src/utils/spinner.ts +11 -7
- package/src/utils/stripAnsi.ts +6 -0
- package/src/utils/table.ts +38 -0
- package/src/styles/gradients.ts +0 -22
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LogLevel, Transport } from '../types';
|
|
2
|
+
import { stripAnsi } from '../utils/stripAnsi';
|
|
3
|
+
|
|
4
|
+
export interface WebhookTransportOptions {
|
|
5
|
+
url: string;
|
|
6
|
+
method?: 'POST' | 'PUT';
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
minLevel?: LogLevel;
|
|
9
|
+
}
|
|
10
|
+
export class WebhookTransport implements Transport {
|
|
11
|
+
name = 'webhook';
|
|
12
|
+
private url: string;
|
|
13
|
+
private method: 'POST' | 'PUT';
|
|
14
|
+
private headers: Record<string, string>;
|
|
15
|
+
constructor(options: WebhookTransportOptions) {
|
|
16
|
+
this.url = options.url;
|
|
17
|
+
this.method = options.method || 'POST';
|
|
18
|
+
this.headers = options.headers || { 'Content-Type': 'application/json' };
|
|
19
|
+
}
|
|
20
|
+
async log(level: LogLevel, message: string, meta?: any): Promise<void> {
|
|
21
|
+
try {
|
|
22
|
+
const payload = {
|
|
23
|
+
timestamp: new Date().toISOString(),
|
|
24
|
+
level: level.toUpperCase(),
|
|
25
|
+
message: stripAnsi(message),
|
|
26
|
+
meta
|
|
27
|
+
};
|
|
28
|
+
await fetch(this.url, {
|
|
29
|
+
method: this.method,
|
|
30
|
+
headers: this.headers,
|
|
31
|
+
body: JSON.stringify(payload)
|
|
32
|
+
});
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.error('[KaiLogger] Webhook transport failed:', e);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type LogLevel = 'debug' | 'info' | 'success' | 'warning' | 'error' | 'silent';
|
|
2
|
+
export const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
success: 2,
|
|
6
|
+
warning: 3,
|
|
7
|
+
error: 4,
|
|
8
|
+
silent: 5
|
|
9
|
+
};
|
|
10
|
+
export interface KaiConfig {
|
|
11
|
+
theme?: string;
|
|
12
|
+
level?: LogLevel;
|
|
13
|
+
timestamp?: 'ISO' | 'locale' | 'relative' | 'none';
|
|
14
|
+
silent?: boolean;
|
|
15
|
+
transports?: Transport[];
|
|
16
|
+
}
|
|
17
|
+
export interface Transport {
|
|
18
|
+
name: string;
|
|
19
|
+
log(level: LogLevel, message: string, meta?: any): void | Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface Formatter {
|
|
22
|
+
format(level: LogLevel, message: string, timestamp: string, scope?: string): string;
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
3
|
+
|
|
4
|
+
export class KaiJson {
|
|
5
|
+
static print(obj: any, theme: any) {
|
|
6
|
+
const jsonStr = JSON.stringify(obj, null, 2);
|
|
7
|
+
|
|
8
|
+
// Manual colorization for full control using KaiChroma
|
|
9
|
+
const colored = jsonStr
|
|
10
|
+
// Strings (keys)
|
|
11
|
+
.replace(/"([^"]+)":/g, (match, key) => {
|
|
12
|
+
return KaiChroma.hex(theme.info[0], `"${key}"`) + ':';
|
|
13
|
+
})
|
|
14
|
+
// String values
|
|
15
|
+
.replace(/: "([^"]*)"/g, (match, val) => {
|
|
16
|
+
return ': ' + KaiChroma.hex(theme.success[1], `"${val}"`);
|
|
17
|
+
})
|
|
18
|
+
// Numbers
|
|
19
|
+
.replace(/: (\d+\.?\d*)/g, (match, num) => {
|
|
20
|
+
return ': ' + KaiChroma.hex(theme.warning[0], num);
|
|
21
|
+
})
|
|
22
|
+
// Booleans
|
|
23
|
+
.replace(/: (true|false)/g, (match, bool) => {
|
|
24
|
+
return ': ' + KaiChroma.hex(theme.error[0], bool);
|
|
25
|
+
})
|
|
26
|
+
// Null
|
|
27
|
+
.replace(/: (null)/g, (match, n) => {
|
|
28
|
+
return ': ' + KaiChroma.hex(theme.dim, n);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(colored);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
|
|
2
|
+
import * as stackTrace from 'stack-trace';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
5
|
+
import { paint } from '../styles/palettes';
|
|
6
|
+
|
|
7
|
+
export class PrettyError {
|
|
8
|
+
static handle(error: Error, theme: any) {
|
|
9
|
+
const trace = stackTrace.parse(error);
|
|
10
|
+
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log(paint.apply(` 💥 ${error.name} `, theme.error));
|
|
13
|
+
console.log(KaiChroma.bold(error.message));
|
|
14
|
+
|
|
15
|
+
// Find the first relevant frame (not node internal)
|
|
16
|
+
const frame = trace.find(t => {
|
|
17
|
+
const file = t.getFileName();
|
|
18
|
+
return file && !file.includes('node_modules') && !file.startsWith('node:');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (frame) {
|
|
22
|
+
const fileName = frame.getFileName();
|
|
23
|
+
const lineNumber = frame.getLineNumber();
|
|
24
|
+
|
|
25
|
+
console.log(KaiChroma.hex('#666666', `at ${fileName}:${lineNumber}`));
|
|
26
|
+
console.log(KaiChroma.hex('#666666', '─'.repeat(50)));
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(fileName, 'utf-8');
|
|
30
|
+
const lines = content.split('\n');
|
|
31
|
+
const start = Math.max(0, lineNumber - 3);
|
|
32
|
+
const end = Math.min(lines.length, lineNumber + 2);
|
|
33
|
+
|
|
34
|
+
for (let i = start; i < end; i++) {
|
|
35
|
+
const isErrorLine = i + 1 === lineNumber;
|
|
36
|
+
const lineNumStr = (i + 1).toString().padEnd(4);
|
|
37
|
+
|
|
38
|
+
if (isErrorLine) {
|
|
39
|
+
const lineContent = KaiChroma.bold(lines[i]);
|
|
40
|
+
console.log(paint.apply(` > ${lineNumStr} | ${lineContent}`, theme.error));
|
|
41
|
+
} else {
|
|
42
|
+
console.log(KaiChroma.hex('#888888', ` ${lineNumStr} | ${lines[i]}`));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Fallback if file cannot be read
|
|
47
|
+
console.log(KaiChroma.dim(' (Source code unavailable)'));
|
|
48
|
+
}
|
|
49
|
+
console.log(KaiChroma.hex('#666666', '─'.repeat(50)));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Show simplified stack
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log(KaiChroma.dim('Stack Trace:'));
|
|
55
|
+
trace.forEach(t => {
|
|
56
|
+
const fn = t.getFunctionName() || '<anonymous>';
|
|
57
|
+
const file = t.getFileName();
|
|
58
|
+
const line = t.getLineNumber();
|
|
59
|
+
if (file && !file.includes('node_modules')) {
|
|
60
|
+
console.log(KaiChroma.dim(` at ${fn} (${file}:${line})`));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
3
|
+
import { palettes, ThemeName } from '../styles/palettes';
|
|
4
|
+
|
|
5
|
+
export class KaiProgress {
|
|
6
|
+
private total: number;
|
|
7
|
+
private current: number;
|
|
8
|
+
private width: number;
|
|
9
|
+
private theme: ThemeName;
|
|
10
|
+
|
|
11
|
+
constructor(total: number, width: number = 40, theme: ThemeName = 'zen') {
|
|
12
|
+
this.total = total;
|
|
13
|
+
this.current = 0;
|
|
14
|
+
this.width = width;
|
|
15
|
+
this.theme = theme;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public update(current: number) {
|
|
19
|
+
this.current = current;
|
|
20
|
+
this.render();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public increment(amount: number = 1) {
|
|
24
|
+
this.current = Math.min(this.total, this.current + amount);
|
|
25
|
+
this.render();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private render() {
|
|
29
|
+
const percentage = Math.min(1, this.current / this.total);
|
|
30
|
+
const filledWidth = Math.round(this.width * percentage);
|
|
31
|
+
const emptyWidth = this.width - filledWidth;
|
|
32
|
+
|
|
33
|
+
const filledChar = '█';
|
|
34
|
+
const emptyChar = '░';
|
|
35
|
+
|
|
36
|
+
const filled = filledChar.repeat(filledWidth);
|
|
37
|
+
const empty = emptyChar.repeat(emptyWidth);
|
|
38
|
+
|
|
39
|
+
const palette = palettes[this.theme];
|
|
40
|
+
const colors = palette.info;
|
|
41
|
+
const dimColor = palette.dim;
|
|
42
|
+
|
|
43
|
+
// Utilizamos KaiChroma.gradient en lugar de gradient-string
|
|
44
|
+
const barFilled = KaiChroma.gradient(colors, filled);
|
|
45
|
+
const barEmpty = KaiChroma.hex(dimColor, empty);
|
|
46
|
+
const bar = barFilled + barEmpty;
|
|
47
|
+
|
|
48
|
+
const percentText = Math.round(percentage * 100).toString().padStart(3);
|
|
49
|
+
|
|
50
|
+
process.stdout.write(`\r${bar} ${percentText}%`);
|
|
51
|
+
|
|
52
|
+
if (this.current >= this.total) {
|
|
53
|
+
process.stdout.write('\n');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
import * as readline from 'readline';
|
|
3
|
+
import { paint } from '../styles/palettes';
|
|
4
|
+
|
|
5
|
+
export class KaiPrompt {
|
|
6
|
+
static ask(question: string, theme: any): Promise<string> {
|
|
7
|
+
const rl = readline.createInterface({
|
|
8
|
+
input: process.stdin,
|
|
9
|
+
output: process.stdout
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const q = paint.apply(`? ${question} `, theme.info);
|
|
13
|
+
|
|
14
|
+
return new Promise(resolve => {
|
|
15
|
+
rl.question(q, (answer) => {
|
|
16
|
+
rl.close();
|
|
17
|
+
resolve(answer);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static confirm(question: string, theme: any): Promise<boolean> {
|
|
23
|
+
return this.ask(`${question} (y/n)`, theme).then(ans => {
|
|
24
|
+
return ans.toLowerCase().startsWith('y');
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
3
|
+
import { paint } from '../styles/palettes';
|
|
4
|
+
import * as readline from 'readline';
|
|
5
|
+
|
|
6
|
+
export class KaiSelection {
|
|
7
|
+
static async select(question: string, options: string[], theme: any): Promise<string> {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
let selectedIndex = 0;
|
|
10
|
+
const stdin = process.stdin;
|
|
11
|
+
const stdout = process.stdout;
|
|
12
|
+
|
|
13
|
+
stdin.setRawMode(true);
|
|
14
|
+
stdin.resume();
|
|
15
|
+
stdin.setEncoding('utf8');
|
|
16
|
+
|
|
17
|
+
const render = () => {
|
|
18
|
+
readline.moveCursor(stdout, 0, -(options.length + 1));
|
|
19
|
+
readline.clearScreenDown(stdout);
|
|
20
|
+
|
|
21
|
+
const q = paint.apply(`? ${question} `, theme.info);
|
|
22
|
+
console.log(q);
|
|
23
|
+
|
|
24
|
+
options.forEach((opt, i) => {
|
|
25
|
+
if (i === selectedIndex) {
|
|
26
|
+
const pointer = paint.apply('>', theme.success);
|
|
27
|
+
const text = paint.apply(opt, theme.success);
|
|
28
|
+
console.log(`${pointer} ${text}`);
|
|
29
|
+
} else {
|
|
30
|
+
console.log(` ${opt}`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
console.log('\n'.repeat(options.length));
|
|
36
|
+
render();
|
|
37
|
+
|
|
38
|
+
const handler = (key: string) => {
|
|
39
|
+
if (key === '\u0003') { // Ctrl+C
|
|
40
|
+
process.exit();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (key === '\u001b[A') { // Up arrow
|
|
44
|
+
selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : options.length - 1;
|
|
45
|
+
render();
|
|
46
|
+
} else if (key === '\u001b[B') { // Down arrow
|
|
47
|
+
selectedIndex = (selectedIndex < options.length - 1) ? selectedIndex + 1 : 0;
|
|
48
|
+
render();
|
|
49
|
+
} else if (key === '\r') { // Enter
|
|
50
|
+
stdin.removeListener('data', handler);
|
|
51
|
+
stdin.setRawMode(false);
|
|
52
|
+
stdin.pause();
|
|
53
|
+
|
|
54
|
+
readline.moveCursor(stdout, 0, -(options.length + 1));
|
|
55
|
+
readline.clearScreenDown(stdout);
|
|
56
|
+
console.log(`${paint.apply(`✔ ${question}`, theme.success)} ${KaiChroma.bold(options[selectedIndex])}`);
|
|
57
|
+
|
|
58
|
+
resolve(options[selectedIndex]);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
stdin.on('data', handler);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static async multiselect(question: string, options: string[], theme: any): Promise<string[]> {
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
let selectedIndex = 0;
|
|
69
|
+
const selected = new Set<number>();
|
|
70
|
+
const stdin = process.stdin;
|
|
71
|
+
const stdout = process.stdout;
|
|
72
|
+
|
|
73
|
+
stdin.setRawMode(true);
|
|
74
|
+
stdin.resume();
|
|
75
|
+
stdin.setEncoding('utf8');
|
|
76
|
+
|
|
77
|
+
const render = () => {
|
|
78
|
+
readline.moveCursor(stdout, 0, -(options.length + 1));
|
|
79
|
+
readline.clearScreenDown(stdout);
|
|
80
|
+
|
|
81
|
+
const q = paint.apply(`? ${question} `, theme.info);
|
|
82
|
+
console.log(`${q} ${KaiChroma.dim('(Space to select, Enter to confirm)')}`);
|
|
83
|
+
|
|
84
|
+
options.forEach((opt, i) => {
|
|
85
|
+
const isSelected = selected.has(i);
|
|
86
|
+
const isHovered = i === selectedIndex;
|
|
87
|
+
|
|
88
|
+
let prefix = isSelected ? paint.apply('◉', theme.success) : '◯';
|
|
89
|
+
let text = opt;
|
|
90
|
+
|
|
91
|
+
if (isHovered) {
|
|
92
|
+
prefix = paint.apply('>', theme.info) + ' ' + prefix;
|
|
93
|
+
text = paint.apply(text, theme.info);
|
|
94
|
+
} else {
|
|
95
|
+
prefix = ' ' + prefix;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(`${prefix} ${text}`);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
console.log('\n'.repeat(options.length));
|
|
103
|
+
render();
|
|
104
|
+
|
|
105
|
+
const handler = (key: string) => {
|
|
106
|
+
if (key === '\u0003') process.exit();
|
|
107
|
+
|
|
108
|
+
if (key === '\u001b[A') { // Up
|
|
109
|
+
selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : options.length - 1;
|
|
110
|
+
render();
|
|
111
|
+
} else if (key === '\u001b[B') { // Down
|
|
112
|
+
selectedIndex = (selectedIndex < options.length - 1) ? selectedIndex + 1 : 0;
|
|
113
|
+
render();
|
|
114
|
+
} else if (key === ' ') { // Space
|
|
115
|
+
if (selected.has(selectedIndex)) selected.delete(selectedIndex);
|
|
116
|
+
else selected.add(selectedIndex);
|
|
117
|
+
render();
|
|
118
|
+
} else if (key === '\r') { // Enter
|
|
119
|
+
stdin.removeListener('data', handler);
|
|
120
|
+
stdin.setRawMode(false);
|
|
121
|
+
stdin.pause();
|
|
122
|
+
|
|
123
|
+
readline.moveCursor(stdout, 0, -(options.length + 1));
|
|
124
|
+
readline.clearScreenDown(stdout);
|
|
125
|
+
|
|
126
|
+
const result = options.filter((_, i) => selected.has(i));
|
|
127
|
+
console.log(`${paint.apply(`✔ ${question}`, theme.success)} ${KaiChroma.bold(result.join(', '))}`);
|
|
128
|
+
|
|
129
|
+
resolve(result);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
stdin.on('data', handler);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/utils/spinner.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
3
3
|
|
|
4
4
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
5
|
+
|
|
5
6
|
export class KaiSpinner {
|
|
6
7
|
private timer: NodeJS.Timeout | null = null;
|
|
7
8
|
private index = 0;
|
|
8
9
|
private text = '';
|
|
9
|
-
private
|
|
10
|
+
private colorHex = '#00FFFF'; // Default cyan-ish
|
|
11
|
+
|
|
10
12
|
start(text: string, colorHex: string = '#00FFFF') {
|
|
11
13
|
this.stop();
|
|
12
14
|
this.text = text;
|
|
13
|
-
this.
|
|
15
|
+
this.colorHex = colorHex;
|
|
14
16
|
process.stdout.write('\x1B[?25l');
|
|
15
17
|
this.timer = setInterval(() => {
|
|
16
18
|
const frame = frames[this.index = ++this.index % frames.length];
|
|
17
|
-
process.stdout.write(`\r${this.
|
|
19
|
+
process.stdout.write(`\r${KaiChroma.hex(this.colorHex, frame)} ${this.text}`);
|
|
18
20
|
}, 80);
|
|
19
21
|
}
|
|
22
|
+
|
|
20
23
|
stop(symbol: string = '✔', endText?: string, colorHex?: string) {
|
|
21
24
|
if (this.timer) {
|
|
22
25
|
clearInterval(this.timer);
|
|
@@ -24,11 +27,12 @@ export class KaiSpinner {
|
|
|
24
27
|
process.stdout.write('\r\x1B[K');
|
|
25
28
|
process.stdout.write('\x1B[?25h');
|
|
26
29
|
if (endText) {
|
|
27
|
-
const finalColor = colorHex
|
|
28
|
-
console.log(`${finalColor
|
|
30
|
+
const finalColor = colorHex || this.colorHex;
|
|
31
|
+
console.log(`${KaiChroma.hex(finalColor, symbol)} ${endText}`);
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
}
|
|
35
|
+
|
|
32
36
|
fail(text: string) {
|
|
33
37
|
this.stop('✖', text, '#FF0000');
|
|
34
38
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
import { KaiChroma } from '../styles/KaiChroma';
|
|
3
|
+
import { paint } from '../styles/palettes';
|
|
4
|
+
|
|
5
|
+
export class KaiTable {
|
|
6
|
+
static print(data: any[], theme: any) {
|
|
7
|
+
if (data.length === 0) return;
|
|
8
|
+
|
|
9
|
+
const keys = Object.keys(data[0]);
|
|
10
|
+
const colWidths = keys.map(key => {
|
|
11
|
+
const maxValLen = Math.max(...data.map(row => String(row[key]).length));
|
|
12
|
+
return Math.max(key.length, maxValLen) + 2;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const createRow = (rowItems: string[], isHeader = false) => {
|
|
16
|
+
return rowItems.map((item, i) => {
|
|
17
|
+
const cell = item.padEnd(colWidths[i]);
|
|
18
|
+
return isHeader
|
|
19
|
+
? paint.apply(cell, theme.info)
|
|
20
|
+
: cell;
|
|
21
|
+
}).join(' │ ');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const separator = colWidths.map(w => '─'.repeat(w)).join('─┼─');
|
|
25
|
+
const dimColor = (text: string) => KaiChroma.hex(theme.dim, text);
|
|
26
|
+
|
|
27
|
+
console.log(dimColor(separator));
|
|
28
|
+
console.log(createRow(keys, true));
|
|
29
|
+
console.log(dimColor(separator));
|
|
30
|
+
|
|
31
|
+
data.forEach(row => {
|
|
32
|
+
const values = keys.map(k => String(row[k]));
|
|
33
|
+
console.log(createRow(values));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log(dimColor(separator));
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/styles/gradients.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import gradient from 'gradient-string';
|
|
2
|
-
import { palettes, ThemeName } from './palettes';
|
|
3
|
-
|
|
4
|
-
export class GradientEngine {
|
|
5
|
-
private currentTheme: ThemeName = 'zen';
|
|
6
|
-
setTheme(theme: ThemeName) {
|
|
7
|
-
if (palettes[theme]) {
|
|
8
|
-
this.currentTheme = theme;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
get text() {
|
|
12
|
-
return palettes[this.currentTheme];
|
|
13
|
-
}
|
|
14
|
-
apply(text: string, colors: string[]) {
|
|
15
|
-
return gradient(colors)(text);
|
|
16
|
-
}
|
|
17
|
-
multiline(text: string, colors: string[]) {
|
|
18
|
-
return gradient(colors).multiline(text);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const paint = new GradientEngine();
|