@vizzly-testing/cli 0.14.0 → 0.15.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.
Files changed (140) hide show
  1. package/dist/cli.js +68 -68
  2. package/dist/commands/doctor.js +30 -34
  3. package/dist/commands/finalize.js +24 -23
  4. package/dist/commands/init.js +30 -28
  5. package/dist/commands/login.js +49 -55
  6. package/dist/commands/logout.js +14 -19
  7. package/dist/commands/project.js +83 -103
  8. package/dist/commands/run.js +77 -89
  9. package/dist/commands/status.js +48 -49
  10. package/dist/commands/tdd-daemon.js +90 -86
  11. package/dist/commands/tdd.js +59 -88
  12. package/dist/commands/upload.js +57 -57
  13. package/dist/commands/whoami.js +40 -45
  14. package/dist/index.js +2 -5
  15. package/dist/plugin-loader.js +15 -17
  16. package/dist/reporter/reporter-bundle.css +1 -1
  17. package/dist/reporter/reporter-bundle.iife.js +74 -41
  18. package/dist/sdk/index.js +36 -45
  19. package/dist/server/handlers/api-handler.js +14 -15
  20. package/dist/server/handlers/tdd-handler.js +34 -37
  21. package/dist/server/http-server.js +75 -869
  22. package/dist/server/middleware/cors.js +22 -0
  23. package/dist/server/middleware/json-parser.js +35 -0
  24. package/dist/server/middleware/response.js +79 -0
  25. package/dist/server/routers/assets.js +91 -0
  26. package/dist/server/routers/auth.js +144 -0
  27. package/dist/server/routers/baseline.js +163 -0
  28. package/dist/server/routers/cloud-proxy.js +146 -0
  29. package/dist/server/routers/config.js +126 -0
  30. package/dist/server/routers/dashboard.js +130 -0
  31. package/dist/server/routers/health.js +61 -0
  32. package/dist/server/routers/projects.js +168 -0
  33. package/dist/server/routers/screenshot.js +86 -0
  34. package/dist/services/auth-service.js +1 -1
  35. package/dist/services/build-manager.js +13 -40
  36. package/dist/services/config-service.js +2 -4
  37. package/dist/services/html-report-generator.js +6 -5
  38. package/dist/services/index.js +64 -0
  39. package/dist/services/project-service.js +121 -40
  40. package/dist/services/screenshot-server.js +9 -9
  41. package/dist/services/server-manager.js +11 -18
  42. package/dist/services/static-report-generator.js +3 -4
  43. package/dist/services/tdd-service.js +246 -103
  44. package/dist/services/test-runner.js +24 -25
  45. package/dist/services/uploader.js +5 -4
  46. package/dist/types/commands/init.d.ts +1 -2
  47. package/dist/types/index.d.ts +2 -3
  48. package/dist/types/plugin-loader.d.ts +1 -2
  49. package/dist/types/reporter/src/api/client.d.ts +178 -0
  50. package/dist/types/reporter/src/components/app-router.d.ts +1 -3
  51. package/dist/types/reporter/src/components/code-block.d.ts +4 -0
  52. package/dist/types/reporter/src/components/comparison/comparison-modes/onion-skin-mode.d.ts +10 -0
  53. package/dist/types/reporter/src/components/comparison/comparison-modes/overlay-mode.d.ts +11 -0
  54. package/dist/types/reporter/src/components/comparison/comparison-modes/shared/base-comparison-mode.d.ts +14 -0
  55. package/dist/types/reporter/src/components/comparison/comparison-modes/shared/image-renderer.d.ts +30 -0
  56. package/dist/types/reporter/src/components/comparison/comparison-modes/toggle-view.d.ts +8 -0
  57. package/dist/types/reporter/src/components/comparison/comparison-viewer.d.ts +4 -0
  58. package/dist/types/reporter/src/components/comparison/screenshot-display.d.ts +16 -0
  59. package/dist/types/reporter/src/components/design-system/alert.d.ts +9 -0
  60. package/dist/types/reporter/src/components/design-system/badge.d.ts +17 -0
  61. package/dist/types/reporter/src/components/design-system/button.d.ts +19 -0
  62. package/dist/types/reporter/src/components/design-system/card.d.ts +31 -0
  63. package/dist/types/reporter/src/components/design-system/empty-state.d.ts +13 -0
  64. package/dist/types/reporter/src/components/design-system/form-controls.d.ts +44 -0
  65. package/dist/types/reporter/src/components/design-system/health-ring.d.ts +7 -0
  66. package/dist/types/reporter/src/components/design-system/index.d.ts +11 -0
  67. package/dist/types/reporter/src/components/design-system/modal.d.ts +10 -0
  68. package/dist/types/reporter/src/components/design-system/skeleton.d.ts +19 -0
  69. package/dist/types/reporter/src/components/design-system/spinner.d.ts +10 -0
  70. package/dist/types/reporter/src/components/design-system/tabs.d.ts +13 -0
  71. package/dist/types/reporter/src/components/layout/header.d.ts +5 -0
  72. package/dist/types/reporter/src/components/layout/index.d.ts +2 -0
  73. package/dist/types/reporter/src/components/layout/layout.d.ts +6 -0
  74. package/dist/types/reporter/src/components/views/builds-view.d.ts +1 -0
  75. package/dist/types/reporter/src/components/views/comparison-detail-view.d.ts +1 -4
  76. package/dist/types/reporter/src/components/views/comparisons-view.d.ts +1 -6
  77. package/dist/types/reporter/src/components/views/stats-view.d.ts +1 -6
  78. package/dist/types/reporter/src/components/waiting-for-screenshots.d.ts +1 -0
  79. package/dist/types/reporter/src/hooks/queries/use-auth-queries.d.ts +15 -0
  80. package/dist/types/reporter/src/hooks/queries/use-cloud-queries.d.ts +6 -0
  81. package/dist/types/reporter/src/hooks/queries/use-config-queries.d.ts +6 -0
  82. package/dist/types/reporter/src/hooks/queries/use-tdd-queries.d.ts +9 -0
  83. package/dist/types/reporter/src/lib/query-client.d.ts +2 -0
  84. package/dist/types/reporter/src/lib/query-keys.d.ts +13 -0
  85. package/dist/types/sdk/index.d.ts +2 -4
  86. package/dist/types/server/handlers/tdd-handler.d.ts +2 -0
  87. package/dist/types/server/http-server.d.ts +1 -1
  88. package/dist/types/server/middleware/cors.d.ts +11 -0
  89. package/dist/types/server/middleware/json-parser.d.ts +10 -0
  90. package/dist/types/server/middleware/response.d.ts +50 -0
  91. package/dist/types/server/routers/assets.d.ts +6 -0
  92. package/dist/types/server/routers/auth.d.ts +9 -0
  93. package/dist/types/server/routers/baseline.d.ts +13 -0
  94. package/dist/types/server/routers/cloud-proxy.d.ts +11 -0
  95. package/dist/types/server/routers/config.d.ts +9 -0
  96. package/dist/types/server/routers/dashboard.d.ts +6 -0
  97. package/dist/types/server/routers/health.d.ts +11 -0
  98. package/dist/types/server/routers/projects.d.ts +9 -0
  99. package/dist/types/server/routers/screenshot.d.ts +11 -0
  100. package/dist/types/services/build-manager.d.ts +4 -3
  101. package/dist/types/services/config-service.d.ts +2 -3
  102. package/dist/types/services/index.d.ts +7 -0
  103. package/dist/types/services/project-service.d.ts +6 -4
  104. package/dist/types/services/screenshot-server.d.ts +5 -5
  105. package/dist/types/services/server-manager.d.ts +5 -3
  106. package/dist/types/services/tdd-service.d.ts +12 -1
  107. package/dist/types/services/test-runner.d.ts +3 -3
  108. package/dist/types/utils/output.d.ts +84 -0
  109. package/dist/utils/config-loader.js +24 -48
  110. package/dist/utils/global-config.js +2 -17
  111. package/dist/utils/output.js +445 -0
  112. package/dist/utils/security.js +3 -4
  113. package/docs/api-reference.md +0 -1
  114. package/docs/plugins.md +22 -22
  115. package/package.json +3 -2
  116. package/dist/container/index.js +0 -215
  117. package/dist/services/base-service.js +0 -154
  118. package/dist/types/container/index.d.ts +0 -59
  119. package/dist/types/reporter/src/components/comparison/viewer-modes/onion-viewer.d.ts +0 -3
  120. package/dist/types/reporter/src/components/comparison/viewer-modes/overlay-viewer.d.ts +0 -3
  121. package/dist/types/reporter/src/components/comparison/viewer-modes/side-by-side-viewer.d.ts +0 -3
  122. package/dist/types/reporter/src/components/comparison/viewer-modes/toggle-viewer.d.ts +0 -3
  123. package/dist/types/reporter/src/components/dashboard/dashboard-header.d.ts +0 -5
  124. package/dist/types/reporter/src/components/dashboard/dashboard-stats.d.ts +0 -4
  125. package/dist/types/reporter/src/components/dashboard/empty-state.d.ts +0 -8
  126. package/dist/types/reporter/src/components/ui/form-field.d.ts +0 -16
  127. package/dist/types/reporter/src/components/ui/status-badge.d.ts +0 -5
  128. package/dist/types/reporter/src/hooks/use-auth.d.ts +0 -10
  129. package/dist/types/reporter/src/hooks/use-baseline-actions.d.ts +0 -5
  130. package/dist/types/reporter/src/hooks/use-config.d.ts +0 -9
  131. package/dist/types/reporter/src/hooks/use-projects.d.ts +0 -10
  132. package/dist/types/reporter/src/hooks/use-report-data.d.ts +0 -7
  133. package/dist/types/reporter/src/hooks/use-vizzly-api.d.ts +0 -9
  134. package/dist/types/services/base-service.d.ts +0 -71
  135. package/dist/types/utils/console-ui.d.ts +0 -61
  136. package/dist/types/utils/logger-factory.d.ts +0 -26
  137. package/dist/types/utils/logger.d.ts +0 -79
  138. package/dist/utils/console-ui.js +0 -241
  139. package/dist/utils/logger-factory.js +0 -76
  140. package/dist/utils/logger.js +0 -231
@@ -1,26 +0,0 @@
1
- /**
2
- * Create a service logger with consistent naming and options
3
- * @param {string} serviceName - Name of the service (e.g., 'TDD', 'SERVER', 'API')
4
- * @param {Object} options - Logger options
5
- * @returns {Logger} Configured logger instance
6
- */
7
- export function createServiceLogger(serviceName: string, options?: any): Logger;
8
- /**
9
- * Create a component logger for CLI commands and utilities
10
- * @param {string} componentName - Name of the component
11
- * @param {Object} options - Logger options
12
- * @returns {Logger} Configured logger instance
13
- */
14
- export function createComponentLogger(componentName: string, options?: any): Logger;
15
- /**
16
- * Create a basic logger with standard defaults
17
- * @param {Object} options - Logger options
18
- * @returns {Logger} Configured logger instance
19
- */
20
- export function createStandardLogger(options?: any): Logger;
21
- /**
22
- * Create a logger for uploader service with specific defaults
23
- * @param {Object} options - Logger options
24
- * @returns {Logger} Configured logger instance
25
- */
26
- export function createUploaderLogger(options?: any): Logger;
@@ -1,79 +0,0 @@
1
- /**
2
- * Create default logger instance
3
- */
4
- export function createLogger(options?: {}): Logger;
5
- /**
6
- * Structured logger with multiple output targets and log levels
7
- */
8
- export class Logger {
9
- constructor(options?: {});
10
- level: any;
11
- logFile: any;
12
- verbose: any;
13
- silent: any;
14
- colors: boolean;
15
- levels: {
16
- error: number;
17
- warn: number;
18
- info: number;
19
- debug: number;
20
- };
21
- /**
22
- * Initialize log file with session header
23
- */
24
- initLogFile(): void;
25
- /**
26
- * Check if message should be logged at current level
27
- */
28
- shouldLog(level: any): boolean;
29
- /**
30
- * Log a message with specified level
31
- */
32
- log(level: any, message: any, data?: {}): void;
33
- /**
34
- * Output formatted message to console
35
- */
36
- outputToConsole(level: any, message: any, data: any): void;
37
- /**
38
- * Get colored prefix for log level
39
- */
40
- getColoredPrefix(level: any): any;
41
- /**
42
- * Convenience methods
43
- */
44
- error(message: any, data?: {}): void;
45
- warn(message: any, data?: {}): void;
46
- info(message: any, data?: {}): void;
47
- debug(message: any, data?: {}): void;
48
- /**
49
- * Log progress updates
50
- */
51
- progress(stage: any, message: any, data?: {}): void;
52
- /**
53
- * Log command execution
54
- */
55
- command(command: any, data?: {}): void;
56
- /**
57
- * Log performance metrics
58
- */
59
- perf(operation: any, duration: any, data?: {}): void;
60
- /**
61
- * Create child logger with additional context
62
- */
63
- child(context?: {}): ChildLogger;
64
- }
65
- /**
66
- * Child logger that inherits from parent with additional context
67
- */
68
- declare class ChildLogger {
69
- constructor(parent: any, context: any);
70
- parent: any;
71
- context: any;
72
- log(level: any, message: any, data?: {}): void;
73
- error(message: any, data?: {}): void;
74
- warn(message: any, data?: {}): void;
75
- info(message: any, data?: {}): void;
76
- debug(message: any, data?: {}): void;
77
- progress(stage: any, message: any, data?: {}): void;
78
- }
79
- export {};
@@ -1,241 +0,0 @@
1
- import { createColors } from './colors.js';
2
-
3
- /**
4
- * Simple console UI utilities for CLI output
5
- */
6
- export class ConsoleUI {
7
- constructor(options = {}) {
8
- this.colors = createColors({
9
- useColor: options.color !== false
10
- });
11
- this.json = options.json || false;
12
- this.verbose = options.verbose || false;
13
- this.spinner = null;
14
- this.lastLine = '';
15
- }
16
-
17
- /**
18
- * Show a success message
19
- */
20
- success(message, data = {}) {
21
- this.stopSpinner();
22
- if (this.json) {
23
- console.log(JSON.stringify({
24
- status: 'success',
25
- message,
26
- timestamp: new Date().toISOString(),
27
- ...data
28
- }));
29
- } else {
30
- console.log(this.colors.green(`✓ ${message}`));
31
- }
32
- }
33
-
34
- /**
35
- * Show an error message and exit
36
- */
37
- error(message, error = {}, exitCode = 1) {
38
- this.stopSpinner();
39
- if (this.json) {
40
- const errorData = {
41
- status: 'error',
42
- message,
43
- timestamp: new Date().toISOString()
44
- };
45
- if (error instanceof Error) {
46
- const errorMessage = error.getUserMessage ? error.getUserMessage() : error.message;
47
- errorData.error = {
48
- name: error.name,
49
- message: errorMessage,
50
- code: error.code,
51
- ...(this.verbose && {
52
- stack: error.stack
53
- })
54
- };
55
- } else if (typeof error === 'object') {
56
- errorData.error = error;
57
- }
58
- console.error(JSON.stringify(errorData));
59
- } else {
60
- console.error(this.colors.red(`✖ ${message}`));
61
-
62
- // Always show error details (not just in verbose mode)
63
- if (error instanceof Error) {
64
- // Use getUserMessage() if available (VizzlyError classes), otherwise use message
65
- const errorMessage = error.getUserMessage ? error.getUserMessage() : error.message;
66
- if (errorMessage && errorMessage !== message) {
67
- console.error(this.colors.dim(errorMessage));
68
- }
69
- // Stack traces only in verbose mode
70
- if (this.verbose && error.stack) {
71
- console.error(this.colors.dim(error.stack));
72
- }
73
- } else if (typeof error === 'string' && error) {
74
- console.error(this.colors.dim(error));
75
- } else if (error && typeof error === 'object') {
76
- // Show error object details if available
77
- try {
78
- const errorStr = JSON.stringify(error, null, 2);
79
- if (errorStr !== '{}') {
80
- console.error(this.colors.dim(errorStr));
81
- }
82
- } catch {
83
- // Fallback for circular references or other JSON.stringify errors
84
- console.error(this.colors.dim(String(error)));
85
- }
86
- }
87
- }
88
- if (exitCode > 0) {
89
- process.exit(exitCode);
90
- }
91
- }
92
-
93
- /**
94
- * Show an info message
95
- */
96
- info(message, data = {}) {
97
- if (this.json) {
98
- console.log(JSON.stringify({
99
- status: 'info',
100
- message,
101
- timestamp: new Date().toISOString(),
102
- ...data
103
- }));
104
- } else {
105
- console.log(this.colors.cyan(`ℹ ${message}`));
106
- }
107
- }
108
-
109
- /**
110
- * Show a warning message
111
- */
112
- warning(message, data = {}) {
113
- if (this.json) {
114
- console.log(JSON.stringify({
115
- status: 'warning',
116
- message,
117
- timestamp: new Date().toISOString(),
118
- ...data
119
- }));
120
- } else {
121
- console.log(this.colors.yellow(`⚠ ${message}`));
122
- }
123
- }
124
-
125
- /**
126
- * Show progress with spinner
127
- */
128
- progress(message, current = 0, total = 0) {
129
- if (this.json) {
130
- console.log(JSON.stringify({
131
- status: 'progress',
132
- message,
133
- progress: {
134
- current,
135
- total
136
- },
137
- timestamp: new Date().toISOString()
138
- }));
139
- } else {
140
- this.updateSpinner(message, current, total);
141
- }
142
- }
143
-
144
- /**
145
- * Update a status line in place (for dynamic updates)
146
- */
147
- updateStatus(line, message) {
148
- if (this.json) {
149
- console.log(JSON.stringify({
150
- status: 'update',
151
- line,
152
- message,
153
- timestamp: new Date().toISOString()
154
- }));
155
- } else {
156
- // Move cursor up to the target line and overwrite it
157
- process.stdout.write(`\u001b[${line}A`); // Move up
158
- process.stdout.write('\u001b[2K'); // Clear line
159
- process.stdout.write('\r'); // Move to beginning
160
- console.log(this.colors.blue(`ℹ ${message}`));
161
- process.stdout.write(`\u001b[${line}B`); // Move back down
162
- }
163
- }
164
-
165
- /**
166
- * Output structured data
167
- */
168
- data(data) {
169
- if (this.json) {
170
- console.log(JSON.stringify({
171
- status: 'data',
172
- data,
173
- timestamp: new Date().toISOString()
174
- }));
175
- } else {
176
- console.log(JSON.stringify(data, null, 2));
177
- }
178
- }
179
-
180
- /**
181
- * Start a spinner with message
182
- */
183
- startSpinner(message) {
184
- if (this.json || !process.stdout.isTTY) return;
185
- this.stopSpinner();
186
- this.currentMessage = message;
187
- const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
188
- let i = 0;
189
- this.spinner = setInterval(() => {
190
- const frame = frames[i++ % frames.length];
191
- const line = `${this.colors.blue(frame)} ${this.currentMessage || message}`;
192
-
193
- // Clear previous line and write new one
194
- process.stdout.write('\r' + ' '.repeat(this.lastLine.length) + '\r');
195
- process.stdout.write(line);
196
- this.lastLine = line;
197
- }, 80);
198
- }
199
-
200
- /**
201
- * Update spinner message and progress
202
- */
203
- updateSpinner(message, current = 0, total = 0) {
204
- if (this.json || !process.stdout.isTTY) return;
205
- if (!this.spinner) {
206
- this.startSpinner(message);
207
- return;
208
- }
209
- const progressText = total > 0 ? ` (${current}/${total})` : '';
210
- const fullMessage = `${message}${progressText}`;
211
-
212
- // The spinner will pick up the new message on next frame
213
- this.currentMessage = fullMessage;
214
- }
215
-
216
- /**
217
- * Stop the spinner
218
- */
219
- stopSpinner() {
220
- if (this.spinner) {
221
- clearInterval(this.spinner);
222
- this.spinner = null;
223
-
224
- // Clear the spinner line
225
- if (process.stdout.isTTY) {
226
- process.stdout.write('\r' + ' '.repeat(this.lastLine.length) + '\r');
227
- }
228
- this.lastLine = '';
229
- }
230
- }
231
-
232
- /**
233
- * Clean up on exit
234
- */
235
- cleanup() {
236
- this.stopSpinner();
237
- }
238
- }
239
-
240
- // Note: Global process event listeners are handled in individual commands
241
- // to avoid interference between tests and proper cleanup
@@ -1,76 +0,0 @@
1
- /**
2
- * Logger Factory
3
- * Centralized logger creation with consistent patterns
4
- */
5
-
6
- import { createLogger } from './logger.js';
7
- import { getLogLevel } from './environment-config.js';
8
-
9
- /**
10
- * Create a service logger with consistent naming and options
11
- * @param {string} serviceName - Name of the service (e.g., 'TDD', 'SERVER', 'API')
12
- * @param {Object} options - Logger options
13
- * @returns {Logger} Configured logger instance
14
- */
15
- export function createServiceLogger(serviceName, options = {}) {
16
- return createLogger({
17
- level: options.level || getLogLevel(),
18
- verbose: options.verbose || false,
19
- silent: options.silent || false,
20
- colors: options.colors !== false,
21
- logFile: options.logFile,
22
- prefix: serviceName,
23
- ...options
24
- });
25
- }
26
-
27
- /**
28
- * Create a component logger for CLI commands and utilities
29
- * @param {string} componentName - Name of the component
30
- * @param {Object} options - Logger options
31
- * @returns {Logger} Configured logger instance
32
- */
33
- export function createComponentLogger(componentName, options = {}) {
34
- return createLogger({
35
- level: options.level || 'info',
36
- verbose: options.verbose || false,
37
- silent: options.silent || false,
38
- colors: options.colors !== false,
39
- logFile: options.logFile,
40
- prefix: componentName,
41
- ...options
42
- });
43
- }
44
-
45
- /**
46
- * Create a basic logger with standard defaults
47
- * @param {Object} options - Logger options
48
- * @returns {Logger} Configured logger instance
49
- */
50
- export function createStandardLogger(options = {}) {
51
- return createLogger({
52
- level: options.level || 'info',
53
- verbose: options.verbose || false,
54
- silent: options.silent || false,
55
- colors: options.colors !== false,
56
- logFile: options.logFile,
57
- ...options
58
- });
59
- }
60
-
61
- /**
62
- * Create a logger for uploader service with specific defaults
63
- * @param {Object} options - Logger options
64
- * @returns {Logger} Configured logger instance
65
- */
66
- export function createUploaderLogger(options = {}) {
67
- return createLogger({
68
- level: options.logLevel || 'info',
69
- verbose: options.verbose || false,
70
- silent: options.silent || false,
71
- colors: options.colors !== false,
72
- logFile: options.logFile,
73
- prefix: 'UPLOADER',
74
- ...options
75
- });
76
- }
@@ -1,231 +0,0 @@
1
- import { writeFileSync, appendFileSync, mkdirSync } from 'fs';
2
- import { join, dirname } from 'path';
3
- import { getEnvironmentDetails } from '../utils/environment.js';
4
- import { getLogLevel } from './environment-config.js';
5
-
6
- /**
7
- * Structured logger with multiple output targets and log levels
8
- */
9
- export class Logger {
10
- constructor(options = {}) {
11
- this.level = options.level || 'info';
12
- this.logFile = options.logFile;
13
- this.verbose = options.verbose || false;
14
- this.silent = options.silent || false;
15
- this.colors = options.colors !== false; // Default to true unless explicitly disabled
16
-
17
- this.levels = {
18
- error: 0,
19
- warn: 1,
20
- info: 2,
21
- debug: 3
22
- };
23
-
24
- // Initialize log file if specified
25
- if (this.logFile) {
26
- this.initLogFile();
27
- }
28
- }
29
-
30
- /**
31
- * Initialize log file with session header
32
- */
33
- initLogFile() {
34
- try {
35
- mkdirSync(dirname(this.logFile), {
36
- recursive: true
37
- });
38
- const sessionHeader = {
39
- timestamp: new Date().toISOString(),
40
- session_start: true,
41
- environment: getEnvironmentDetails(),
42
- pid: process.pid,
43
- node_version: process.version,
44
- platform: process.platform
45
- };
46
- writeFileSync(this.logFile, JSON.stringify(sessionHeader) + '\n');
47
- } catch (error) {
48
- console.error('Failed to initialize log file:', error.message);
49
- }
50
- }
51
-
52
- /**
53
- * Check if message should be logged at current level
54
- */
55
- shouldLog(level) {
56
- return this.levels[level] <= this.levels[this.level];
57
- }
58
-
59
- /**
60
- * Log a message with specified level
61
- */
62
- log(level, message, data = {}) {
63
- if (!this.shouldLog(level)) return;
64
- const logEntry = {
65
- timestamp: new Date().toISOString(),
66
- level,
67
- message,
68
- ...data
69
- };
70
-
71
- // Write to log file if configured
72
- if (this.logFile) {
73
- try {
74
- appendFileSync(this.logFile, JSON.stringify(logEntry) + '\n');
75
- } catch {
76
- // Silently fail to avoid infinite loops
77
- }
78
- }
79
-
80
- // Output to console unless silent
81
- if (!this.silent) {
82
- this.outputToConsole(level, message, data);
83
- }
84
- }
85
-
86
- /**
87
- * Output formatted message to console
88
- */
89
- outputToConsole(level, message, data) {
90
- const prefix = this.getColoredPrefix(level);
91
- const formattedMessage = `${prefix} ${message}`;
92
-
93
- // Use appropriate console method
94
- switch (level) {
95
- case 'error':
96
- console.error(formattedMessage);
97
- if (this.verbose && data.stack) {
98
- console.error(data.stack);
99
- }
100
- break;
101
- case 'warn':
102
- console.warn(formattedMessage);
103
- break;
104
- case 'debug':
105
- if (this.verbose) {
106
- console.log(formattedMessage);
107
- if (Object.keys(data).length > 0) {
108
- console.log(' Data:', JSON.stringify(data, null, 2));
109
- }
110
- }
111
- break;
112
- default:
113
- console.log(formattedMessage);
114
- }
115
- }
116
-
117
- /**
118
- * Get colored prefix for log level
119
- */
120
- getColoredPrefix(level) {
121
- if (!this.colors) {
122
- return `[${level.toUpperCase()}]`;
123
- }
124
- const colors = {
125
- error: '\x1b[31m✖\x1b[0m',
126
- // Red X
127
- warn: '\x1b[33m⚠\x1b[0m',
128
- // Yellow warning
129
- info: '\x1b[36mℹ\x1b[0m',
130
- // Cyan info
131
- debug: '\x1b[35m🔍\x1b[0m' // Magenta debug
132
- };
133
- return colors[level] || `[${level.toUpperCase()}]`;
134
- }
135
-
136
- /**
137
- * Convenience methods
138
- */
139
- error(message, data = {}) {
140
- this.log('error', message, data);
141
- }
142
- warn(message, data = {}) {
143
- this.log('warn', message, data);
144
- }
145
- info(message, data = {}) {
146
- this.log('info', message, data);
147
- }
148
- debug(message, data = {}) {
149
- this.log('debug', message, data);
150
- }
151
-
152
- /**
153
- * Log progress updates
154
- */
155
- progress(stage, message, data = {}) {
156
- this.info(`[${stage}] ${message}`, data);
157
- }
158
-
159
- /**
160
- * Log command execution
161
- */
162
- command(command, data = {}) {
163
- this.debug(`Executing command: ${command}`, data);
164
- }
165
-
166
- /**
167
- * Log performance metrics
168
- */
169
- perf(operation, duration, data = {}) {
170
- this.debug(`${operation} completed in ${duration}ms`, data);
171
- }
172
-
173
- /**
174
- * Create child logger with additional context
175
- */
176
- child(context = {}) {
177
- return new ChildLogger(this, context);
178
- }
179
- }
180
-
181
- /**
182
- * Child logger that inherits from parent with additional context
183
- */
184
- class ChildLogger {
185
- constructor(parent, context) {
186
- this.parent = parent;
187
- this.context = context;
188
- }
189
- log(level, message, data = {}) {
190
- this.parent.log(level, message, {
191
- ...this.context,
192
- ...data
193
- });
194
- }
195
- error(message, data = {}) {
196
- this.log('error', message, data);
197
- }
198
- warn(message, data = {}) {
199
- this.log('warn', message, data);
200
- }
201
- info(message, data = {}) {
202
- this.log('info', message, data);
203
- }
204
- debug(message, data = {}) {
205
- this.log('debug', message, data);
206
- }
207
- progress(stage, message, data = {}) {
208
- this.info(`[${stage}] ${message}`, data);
209
- }
210
- }
211
-
212
- /**
213
- * Create default logger instance
214
- */
215
- export function createLogger(options = {}) {
216
- // Auto-detect color support
217
- const supportsColor = process.stdout.isTTY && process.env.TERM !== 'dumb' && !process.env.NO_COLOR && !options.noColor;
218
-
219
- // Determine log level from environment
220
- const level = options.level || getLogLevel();
221
-
222
- // Create log file path if verbose mode
223
- const logFile = options.verbose ? join(process.cwd(), '.vizzly', 'debug.log') : options.logFile;
224
- return new Logger({
225
- level,
226
- logFile,
227
- verbose: options.verbose,
228
- silent: options.silent,
229
- colors: supportsColor && options.colors !== false
230
- });
231
- }