@yeseh/cortex-cli 0.6.3 → 0.6.4
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/package.json +1 -1
- package/src/observability.spec.ts +8 -21
- package/src/observability.ts +26 -7
- package/src/program.ts +1 -1
package/package.json
CHANGED
|
@@ -27,22 +27,17 @@ describe('createCliLogger', () => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
describe('info()', () => {
|
|
30
|
-
it('should write info log to stderr
|
|
30
|
+
it('should write human-friendly info log to stderr', () => {
|
|
31
31
|
const logger = createCliLogger();
|
|
32
32
|
logger.info('hello world');
|
|
33
33
|
expect(stderrLines.length).toBe(1);
|
|
34
|
-
|
|
35
|
-
expect(parsed.level).toBe('info');
|
|
36
|
-
expect(parsed.msg).toBe('hello world');
|
|
37
|
-
expect(parsed.ts).toBeDefined();
|
|
34
|
+
expect(stderrLines[0]).toBe('INFO: hello world\n');
|
|
38
35
|
});
|
|
39
36
|
|
|
40
37
|
it('should include metadata in the log line', () => {
|
|
41
38
|
const logger = createCliLogger();
|
|
42
39
|
logger.info('test', { store: 'default', count: 5 });
|
|
43
|
-
|
|
44
|
-
expect(parsed.store).toBe('default');
|
|
45
|
-
expect(parsed.count).toBe(5);
|
|
40
|
+
expect(stderrLines[0]).toBe('INFO: test store=default count=5\n');
|
|
46
41
|
});
|
|
47
42
|
});
|
|
48
43
|
|
|
@@ -51,9 +46,7 @@ describe('createCliLogger', () => {
|
|
|
51
46
|
const logger = createCliLogger();
|
|
52
47
|
logger.warn('warning message');
|
|
53
48
|
expect(stderrLines.length).toBe(1);
|
|
54
|
-
|
|
55
|
-
expect(parsed.level).toBe('warn');
|
|
56
|
-
expect(parsed.msg).toBe('warning message');
|
|
49
|
+
expect(stderrLines[0]).toBe('WARN: warning message\n');
|
|
57
50
|
});
|
|
58
51
|
});
|
|
59
52
|
|
|
@@ -62,25 +55,20 @@ describe('createCliLogger', () => {
|
|
|
62
55
|
const logger = createCliLogger();
|
|
63
56
|
logger.error('something failed', new Error('boom'));
|
|
64
57
|
expect(stderrLines.length).toBe(1);
|
|
65
|
-
|
|
66
|
-
expect(parsed.level).toBe('error');
|
|
67
|
-
expect(parsed.msg).toBe('something failed');
|
|
68
|
-
expect(parsed.error).toBe('boom');
|
|
58
|
+
expect(stderrLines[0]).toBe('ERROR: something failed error=boom\n');
|
|
69
59
|
});
|
|
70
60
|
|
|
71
61
|
it('should handle string error argument', () => {
|
|
72
62
|
const logger = createCliLogger();
|
|
73
63
|
logger.error('failed', 'string error');
|
|
74
|
-
|
|
75
|
-
expect(parsed.error).toBe('string error');
|
|
64
|
+
expect(stderrLines[0]).toBe('ERROR: failed error="string error"\n');
|
|
76
65
|
});
|
|
77
66
|
|
|
78
67
|
it('should handle missing error argument', () => {
|
|
79
68
|
const logger = createCliLogger();
|
|
80
69
|
logger.error('failed');
|
|
81
70
|
expect(stderrLines.length).toBe(1);
|
|
82
|
-
|
|
83
|
-
expect(parsed.error).toBeUndefined();
|
|
71
|
+
expect(stderrLines[0]).toBe('ERROR: failed\n');
|
|
84
72
|
});
|
|
85
73
|
});
|
|
86
74
|
|
|
@@ -97,8 +85,7 @@ describe('createCliLogger', () => {
|
|
|
97
85
|
const logger = createCliLogger();
|
|
98
86
|
logger.debug('debug message');
|
|
99
87
|
expect(stderrLines.length).toBe(1);
|
|
100
|
-
|
|
101
|
-
expect(parsed.level).toBe('debug');
|
|
88
|
+
expect(stderrLines[0]).toBe('DEBUG: debug message\n');
|
|
102
89
|
});
|
|
103
90
|
|
|
104
91
|
it('should write debug output when DEBUG includes cortex alongside other values', () => {
|
package/src/observability.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI observability — plain ConsoleLogger writing
|
|
2
|
+
* CLI observability — plain ConsoleLogger writing human-readable lines to stderr.
|
|
3
3
|
*
|
|
4
4
|
* No OTel SDK dependency — keeps the CLI binary small.
|
|
5
5
|
* Debug output is gated by the `DEBUG=cortex` environment variable.
|
|
@@ -11,7 +11,7 @@ import type { Logger } from '@yeseh/cortex-core';
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates a plain console logger for CLI usage.
|
|
13
13
|
*
|
|
14
|
-
* Writes
|
|
14
|
+
* Writes human-readable log lines to stderr (not stdout) to avoid
|
|
15
15
|
* polluting piped command output. Debug output is gated by the
|
|
16
16
|
* `DEBUG=cortex` environment variable.
|
|
17
17
|
*
|
|
@@ -21,7 +21,7 @@ import type { Logger } from '@yeseh/cortex-core';
|
|
|
21
21
|
* ```typescript
|
|
22
22
|
* const logger = createCliLogger();
|
|
23
23
|
* logger.info('Starting command', { store: 'global' });
|
|
24
|
-
* // →
|
|
24
|
+
* // → INFO: Starting command store=global
|
|
25
25
|
* ```
|
|
26
26
|
*
|
|
27
27
|
* @example
|
|
@@ -34,10 +34,27 @@ export const createCliLogger = (): Logger => {
|
|
|
34
34
|
const debugEnabled =
|
|
35
35
|
typeof process.env.DEBUG === 'string' && process.env.DEBUG.includes('cortex');
|
|
36
36
|
|
|
37
|
+
const stringifyMetaValue = (value: unknown): string => {
|
|
38
|
+
if (typeof value === 'string') {
|
|
39
|
+
return value.includes(' ') ? JSON.stringify(value) : value;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value === 'number' || typeof value === 'boolean' || value === null) {
|
|
42
|
+
return String(value);
|
|
43
|
+
}
|
|
44
|
+
return JSON.stringify(value);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const formatMeta = (meta?: Record<string, unknown>): string => {
|
|
48
|
+
if (!meta || Object.keys(meta).length === 0) return '';
|
|
49
|
+
return Object.entries(meta)
|
|
50
|
+
.map(([key, value]) => `${key}=${stringifyMetaValue(value)}`)
|
|
51
|
+
.join(' ');
|
|
52
|
+
};
|
|
53
|
+
|
|
37
54
|
const write = (level: string, msg: string, meta?: Record<string, unknown>): void => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
);
|
|
55
|
+
const line = `${level.toUpperCase()}: ${msg}`;
|
|
56
|
+
const metaText = formatMeta(meta);
|
|
57
|
+
process.stderr.write(metaText.length > 0 ? `${line} ${metaText}\n` : `${line}\n`);
|
|
41
58
|
};
|
|
42
59
|
|
|
43
60
|
return {
|
|
@@ -53,7 +70,9 @@ export const createCliLogger = (): Logger => {
|
|
|
53
70
|
error(msg: string, err?: Error | unknown, meta?: Record<string, unknown>): void {
|
|
54
71
|
const errMeta =
|
|
55
72
|
err instanceof Error
|
|
56
|
-
?
|
|
73
|
+
? debugEnabled
|
|
74
|
+
? { error: err.message, stack: err.stack }
|
|
75
|
+
: { error: err.message }
|
|
57
76
|
: err !== null && err !== undefined
|
|
58
77
|
? { error: String(err) }
|
|
59
78
|
: {};
|
package/src/program.ts
CHANGED
|
@@ -65,7 +65,7 @@ export const runProgram = async (): Promise<void> => {
|
|
|
65
65
|
// This catch handles any unexpected errors that slip through.
|
|
66
66
|
const logger = createCliLogger();
|
|
67
67
|
if (error instanceof Error) {
|
|
68
|
-
logger.error(
|
|
68
|
+
logger.error(error.message);
|
|
69
69
|
}
|
|
70
70
|
else {
|
|
71
71
|
logger.error('An unexpected error occurred');
|