@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeseh/cortex-cli",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -27,22 +27,17 @@ describe('createCliLogger', () => {
27
27
  });
28
28
 
29
29
  describe('info()', () => {
30
- it('should write info log to stderr as JSON', () => {
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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
- const parsed = JSON.parse(stderrLines[0]!);
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', () => {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI observability — plain ConsoleLogger writing structured JSON to stderr.
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 structured JSON log lines to stderr (not stdout) to avoid
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
- * // → {"ts":"2024-01-01T00:00:00.000Z","level":"info","msg":"Starting command","store":"global"}
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
- process.stderr.write(
39
- JSON.stringify({ ts: new Date().toISOString(), level, msg, ...meta }) + '\n'
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
- ? { error: err.message, stack: err.stack }
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(`Error: ${error.message}`, error);
68
+ logger.error(error.message);
69
69
  }
70
70
  else {
71
71
  logger.error('An unexpected error occurred');