@vizzly-testing/cli 0.13.4 → 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 (143) 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 +78 -32
  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/fullscreen-viewer.d.ts +13 -0
  59. package/dist/types/reporter/src/components/comparison/screenshot-display.d.ts +16 -0
  60. package/dist/types/reporter/src/components/comparison/screenshot-list.d.ts +9 -0
  61. package/dist/types/reporter/src/components/comparison/variant-selector.d.ts +1 -1
  62. package/dist/types/reporter/src/components/design-system/alert.d.ts +9 -0
  63. package/dist/types/reporter/src/components/design-system/badge.d.ts +17 -0
  64. package/dist/types/reporter/src/components/design-system/button.d.ts +19 -0
  65. package/dist/types/reporter/src/components/design-system/card.d.ts +31 -0
  66. package/dist/types/reporter/src/components/design-system/empty-state.d.ts +13 -0
  67. package/dist/types/reporter/src/components/design-system/form-controls.d.ts +44 -0
  68. package/dist/types/reporter/src/components/design-system/health-ring.d.ts +7 -0
  69. package/dist/types/reporter/src/components/design-system/index.d.ts +11 -0
  70. package/dist/types/reporter/src/components/design-system/modal.d.ts +10 -0
  71. package/dist/types/reporter/src/components/design-system/skeleton.d.ts +19 -0
  72. package/dist/types/reporter/src/components/design-system/spinner.d.ts +10 -0
  73. package/dist/types/reporter/src/components/design-system/tabs.d.ts +13 -0
  74. package/dist/types/reporter/src/components/layout/header.d.ts +5 -0
  75. package/dist/types/reporter/src/components/layout/index.d.ts +2 -0
  76. package/dist/types/reporter/src/components/layout/layout.d.ts +6 -0
  77. package/dist/types/reporter/src/components/views/builds-view.d.ts +1 -0
  78. package/dist/types/reporter/src/components/views/comparison-detail-view.d.ts +5 -0
  79. package/dist/types/reporter/src/components/views/comparisons-view.d.ts +5 -6
  80. package/dist/types/reporter/src/components/views/stats-view.d.ts +1 -6
  81. package/dist/types/reporter/src/components/waiting-for-screenshots.d.ts +1 -0
  82. package/dist/types/reporter/src/hooks/queries/use-auth-queries.d.ts +15 -0
  83. package/dist/types/reporter/src/hooks/queries/use-cloud-queries.d.ts +6 -0
  84. package/dist/types/reporter/src/hooks/queries/use-config-queries.d.ts +6 -0
  85. package/dist/types/reporter/src/hooks/queries/use-tdd-queries.d.ts +9 -0
  86. package/dist/types/reporter/src/lib/query-client.d.ts +2 -0
  87. package/dist/types/reporter/src/lib/query-keys.d.ts +13 -0
  88. package/dist/types/sdk/index.d.ts +2 -4
  89. package/dist/types/server/handlers/tdd-handler.d.ts +2 -0
  90. package/dist/types/server/http-server.d.ts +1 -1
  91. package/dist/types/server/middleware/cors.d.ts +11 -0
  92. package/dist/types/server/middleware/json-parser.d.ts +10 -0
  93. package/dist/types/server/middleware/response.d.ts +50 -0
  94. package/dist/types/server/routers/assets.d.ts +6 -0
  95. package/dist/types/server/routers/auth.d.ts +9 -0
  96. package/dist/types/server/routers/baseline.d.ts +13 -0
  97. package/dist/types/server/routers/cloud-proxy.d.ts +11 -0
  98. package/dist/types/server/routers/config.d.ts +9 -0
  99. package/dist/types/server/routers/dashboard.d.ts +6 -0
  100. package/dist/types/server/routers/health.d.ts +11 -0
  101. package/dist/types/server/routers/projects.d.ts +9 -0
  102. package/dist/types/server/routers/screenshot.d.ts +11 -0
  103. package/dist/types/services/build-manager.d.ts +4 -3
  104. package/dist/types/services/config-service.d.ts +2 -3
  105. package/dist/types/services/index.d.ts +7 -0
  106. package/dist/types/services/project-service.d.ts +6 -4
  107. package/dist/types/services/screenshot-server.d.ts +5 -5
  108. package/dist/types/services/server-manager.d.ts +5 -3
  109. package/dist/types/services/tdd-service.d.ts +12 -1
  110. package/dist/types/services/test-runner.d.ts +3 -3
  111. package/dist/types/utils/output.d.ts +84 -0
  112. package/dist/utils/config-loader.js +24 -48
  113. package/dist/utils/global-config.js +2 -17
  114. package/dist/utils/output.js +445 -0
  115. package/dist/utils/security.js +3 -4
  116. package/docs/api-reference.md +0 -1
  117. package/docs/plugins.md +22 -22
  118. package/package.json +3 -2
  119. package/dist/container/index.js +0 -215
  120. package/dist/services/base-service.js +0 -154
  121. package/dist/types/container/index.d.ts +0 -59
  122. package/dist/types/reporter/src/components/comparison/viewer-modes/onion-viewer.d.ts +0 -3
  123. package/dist/types/reporter/src/components/comparison/viewer-modes/overlay-viewer.d.ts +0 -3
  124. package/dist/types/reporter/src/components/comparison/viewer-modes/side-by-side-viewer.d.ts +0 -3
  125. package/dist/types/reporter/src/components/comparison/viewer-modes/toggle-viewer.d.ts +0 -3
  126. package/dist/types/reporter/src/components/dashboard/dashboard-header.d.ts +0 -5
  127. package/dist/types/reporter/src/components/dashboard/dashboard-stats.d.ts +0 -4
  128. package/dist/types/reporter/src/components/dashboard/empty-state.d.ts +0 -8
  129. package/dist/types/reporter/src/components/ui/form-field.d.ts +0 -16
  130. package/dist/types/reporter/src/components/ui/status-badge.d.ts +0 -5
  131. package/dist/types/reporter/src/hooks/use-auth.d.ts +0 -10
  132. package/dist/types/reporter/src/hooks/use-baseline-actions.d.ts +0 -5
  133. package/dist/types/reporter/src/hooks/use-config.d.ts +0 -9
  134. package/dist/types/reporter/src/hooks/use-projects.d.ts +0 -10
  135. package/dist/types/reporter/src/hooks/use-report-data.d.ts +0 -7
  136. package/dist/types/reporter/src/hooks/use-vizzly-api.d.ts +0 -9
  137. package/dist/types/services/base-service.d.ts +0 -71
  138. package/dist/types/utils/console-ui.d.ts +0 -61
  139. package/dist/types/utils/logger-factory.d.ts +0 -26
  140. package/dist/types/utils/logger.d.ts +0 -79
  141. package/dist/utils/console-ui.js +0 -241
  142. package/dist/utils/logger-factory.js +0 -76
  143. package/dist/utils/logger.js +0 -231
@@ -3,7 +3,6 @@
3
3
  * Manages reading and writing Vizzly configuration files
4
4
  */
5
5
 
6
- import { BaseService } from './base-service.js';
7
6
  import { cosmiconfigSync } from 'cosmiconfig';
8
7
  import { writeFile, readFile } from 'fs/promises';
9
8
  import { join } from 'path';
@@ -13,11 +12,10 @@ import { loadGlobalConfig, saveGlobalConfig, getGlobalConfigPath } from '../util
13
12
 
14
13
  /**
15
14
  * ConfigService for reading and writing configuration
16
- * @extends BaseService
17
15
  */
18
- export class ConfigService extends BaseService {
16
+ export class ConfigService {
19
17
  constructor(config, options = {}) {
20
- super(config, options);
18
+ this.config = config;
21
19
  this.projectRoot = options.projectRoot || process.cwd();
22
20
  this.explorer = cosmiconfigSync('vizzly');
23
21
  }
@@ -7,8 +7,7 @@ import { writeFile, mkdir } from 'fs/promises';
7
7
  import { existsSync } from 'fs';
8
8
  import { join, relative, dirname } from 'path';
9
9
  import { fileURLToPath } from 'url';
10
- import { createServiceLogger } from '../utils/logger-factory.js';
11
- const logger = createServiceLogger('HTML-REPORT');
10
+ import * as output from '../utils/output.js';
12
11
  export class HtmlReportGenerator {
13
12
  constructor(workingDir, config) {
14
13
  this.workingDir = workingDir;
@@ -93,10 +92,12 @@ export class HtmlReportGenerator {
93
92
  recursive: true
94
93
  });
95
94
  await writeFile(this.reportPath, htmlContent, 'utf8');
96
- logger.debug(`HTML report generated: ${this.reportPath}`);
95
+ output.debug('report', 'generated html report');
97
96
  return this.reportPath;
98
97
  } catch (error) {
99
- logger.error(`Failed to generate HTML report: ${error.message}`);
98
+ output.debug('report', 'html generation failed', {
99
+ error: error.message
100
+ });
100
101
  throw new Error(`Report generation failed: ${error.message}`);
101
102
  }
102
103
  }
@@ -108,7 +109,7 @@ export class HtmlReportGenerator {
108
109
  */
109
110
  processComparison(comparison) {
110
111
  if (!comparison || typeof comparison !== 'object') {
111
- logger.warn('Invalid comparison object provided');
112
+ output.warn('Invalid comparison object provided');
112
113
  return null;
113
114
  }
114
115
  return {
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Service Factory
3
+ * Creates all services with explicit dependencies - no DI container needed
4
+ */
5
+
6
+ import { ApiService } from './api-service.js';
7
+ import { AuthService } from './auth-service.js';
8
+ import { ConfigService } from './config-service.js';
9
+ import { ProjectService } from './project-service.js';
10
+ import { createUploader } from './uploader.js';
11
+ import { BuildManager } from './build-manager.js';
12
+ import { ServerManager } from './server-manager.js';
13
+ import { createTDDService } from './tdd-service.js';
14
+ import { TestRunner } from './test-runner.js';
15
+
16
+ /**
17
+ * Create all services with their dependencies
18
+ * @param {Object} config - Configuration object
19
+ * @param {string} [command='run'] - Command context ('run', 'tdd', 'status')
20
+ * @returns {Object} Services object
21
+ */
22
+ export function createServices(config, command = 'run') {
23
+ let apiService = new ApiService({
24
+ ...config,
25
+ allowNoToken: true
26
+ });
27
+ let authService = new AuthService({
28
+ baseUrl: config.apiUrl
29
+ });
30
+ let configService = new ConfigService(config, {
31
+ projectRoot: process.cwd()
32
+ });
33
+ let projectService = new ProjectService(config, {
34
+ apiService,
35
+ authService
36
+ });
37
+ let uploader = createUploader({
38
+ ...config,
39
+ command
40
+ });
41
+ let buildManager = new BuildManager(config);
42
+ let tddService = createTDDService(config, {
43
+ authService
44
+ });
45
+ let serverManager = new ServerManager(config, {
46
+ services: {
47
+ configService,
48
+ authService,
49
+ projectService
50
+ }
51
+ });
52
+ let testRunner = new TestRunner(config, buildManager, serverManager, tddService);
53
+ return {
54
+ apiService,
55
+ authService,
56
+ configService,
57
+ projectService,
58
+ uploader,
59
+ buildManager,
60
+ serverManager,
61
+ tddService,
62
+ testRunner
63
+ };
64
+ }
@@ -3,18 +3,17 @@
3
3
  * Manages project mappings and project-related operations
4
4
  */
5
5
 
6
- import { BaseService } from './base-service.js';
7
6
  import { VizzlyError } from '../errors/vizzly-error.js';
8
7
  import { getProjectMappings, saveProjectMapping, deleteProjectMapping, getProjectMapping } from '../utils/global-config.js';
9
8
 
10
9
  /**
11
10
  * ProjectService for managing project mappings and operations
12
- * @extends BaseService
13
11
  */
14
- export class ProjectService extends BaseService {
12
+ export class ProjectService {
15
13
  constructor(config, options = {}) {
16
- super(config, options);
14
+ this.config = config;
17
15
  this.apiService = options.apiService;
16
+ this.authService = options.authService;
18
17
  }
19
18
 
20
19
  /**
@@ -100,22 +99,64 @@ export class ProjectService extends BaseService {
100
99
 
101
100
  /**
102
101
  * List all projects from API
103
- * @returns {Promise<Array>} Array of projects
102
+ * Uses OAuth authentication (authService) when available, falls back to API token
103
+ * @returns {Promise<Array>} Array of projects with organization info
104
104
  */
105
105
  async listProjects() {
106
- if (!this.apiService) {
107
- // Return empty array if not authenticated - this is expected in local mode
108
- return [];
106
+ // Try OAuth-based request first (user login via device flow)
107
+ if (this.authService) {
108
+ try {
109
+ // First get the user's organizations via whoami
110
+ let whoami = await this.authService.authenticatedRequest('/api/auth/cli/whoami', {
111
+ method: 'GET'
112
+ });
113
+ let organizations = whoami.organizations || [];
114
+ if (organizations.length === 0) {
115
+ return [];
116
+ }
117
+
118
+ // Fetch projects for each organization
119
+ let allProjects = [];
120
+ for (let org of organizations) {
121
+ try {
122
+ let response = await this.authService.authenticatedRequest('/api/project', {
123
+ method: 'GET',
124
+ headers: {
125
+ 'X-Organization': org.slug
126
+ }
127
+ });
128
+
129
+ // Add organization info to each project
130
+ let projects = (response.projects || []).map(project => ({
131
+ ...project,
132
+ organizationSlug: org.slug,
133
+ organizationName: org.name
134
+ }));
135
+ allProjects.push(...projects);
136
+ } catch {
137
+ // Silently skip failed orgs
138
+ }
139
+ }
140
+ return allProjects;
141
+ } catch {
142
+ // Fall back to API token
143
+ }
109
144
  }
110
- try {
111
- let response = await this.apiService.request('/api/cli/projects', {
112
- method: 'GET'
113
- });
114
- return response.projects || [];
115
- } catch {
116
- // Return empty array on error - likely not authenticated
117
- return [];
145
+
146
+ // Fall back to API token-based request (tokens are org-scoped, so no org header needed)
147
+ if (this.apiService) {
148
+ try {
149
+ let response = await this.apiService.request('/api/project', {
150
+ method: 'GET'
151
+ });
152
+ return response.projects || [];
153
+ } catch {
154
+ return [];
155
+ }
118
156
  }
157
+
158
+ // No authentication available
159
+ return [];
119
160
  }
120
161
 
121
162
  /**
@@ -125,23 +166,43 @@ export class ProjectService extends BaseService {
125
166
  * @returns {Promise<Object>} Project details
126
167
  */
127
168
  async getProject(projectSlug, organizationSlug) {
128
- if (!this.apiService) {
129
- throw new VizzlyError('API service not available', 'NO_API_SERVICE');
169
+ // Try OAuth-based request first
170
+ if (this.authService) {
171
+ try {
172
+ let response = await this.authService.authenticatedRequest(`/api/project/${projectSlug}`, {
173
+ method: 'GET',
174
+ headers: {
175
+ 'X-Organization': organizationSlug
176
+ }
177
+ });
178
+ return response.project || response;
179
+ } catch {
180
+ // Fall back to API token
181
+ }
130
182
  }
131
- try {
132
- let response = await this.apiService.request(`/api/cli/organizations/${organizationSlug}/projects/${projectSlug}`, {
133
- method: 'GET'
134
- });
135
- return response.project;
136
- } catch (error) {
137
- throw new VizzlyError(`Failed to fetch project: ${error.message}`, 'PROJECT_FETCH_FAILED', {
138
- originalError: error
139
- });
183
+
184
+ // Fall back to API token
185
+ if (this.apiService) {
186
+ try {
187
+ let response = await this.apiService.request(`/api/project/${projectSlug}`, {
188
+ method: 'GET',
189
+ headers: {
190
+ 'X-Organization': organizationSlug
191
+ }
192
+ });
193
+ return response.project || response;
194
+ } catch (error) {
195
+ throw new VizzlyError(`Failed to fetch project: ${error.message}`, 'PROJECT_FETCH_FAILED', {
196
+ originalError: error
197
+ });
198
+ }
140
199
  }
200
+ throw new VizzlyError('No authentication available', 'NO_AUTH_SERVICE');
141
201
  }
142
202
 
143
203
  /**
144
204
  * Get recent builds for a project
205
+ * Uses OAuth authentication (authService) when available, falls back to API token
145
206
  * @param {string} projectSlug - Project slug
146
207
  * @param {string} organizationSlug - Organization slug
147
208
  * @param {Object} options - Query options
@@ -150,24 +211,44 @@ export class ProjectService extends BaseService {
150
211
  * @returns {Promise<Array>} Array of builds
151
212
  */
152
213
  async getRecentBuilds(projectSlug, organizationSlug, options = {}) {
153
- if (!this.apiService) {
154
- // Return empty array if not authenticated
155
- return [];
156
- }
157
214
  let queryParams = new globalThis.URLSearchParams();
158
215
  if (options.limit) queryParams.append('limit', String(options.limit));
159
216
  if (options.branch) queryParams.append('branch', options.branch);
160
217
  let query = queryParams.toString();
161
- let url = `/api/cli/organizations/${organizationSlug}/projects/${projectSlug}/builds${query ? `?${query}` : ''}`;
162
- try {
163
- let response = await this.apiService.request(url, {
164
- method: 'GET'
165
- });
166
- return response.builds || [];
167
- } catch {
168
- // Return empty array on error
169
- return [];
218
+ let url = `/api/build/${projectSlug}${query ? `?${query}` : ''}`;
219
+
220
+ // Try OAuth-based request first (user login via device flow)
221
+ if (this.authService) {
222
+ try {
223
+ let response = await this.authService.authenticatedRequest(url, {
224
+ method: 'GET',
225
+ headers: {
226
+ 'X-Organization': organizationSlug
227
+ }
228
+ });
229
+ return response.builds || [];
230
+ } catch {
231
+ // Fall back to API token
232
+ }
170
233
  }
234
+
235
+ // Fall back to API token-based request
236
+ if (this.apiService) {
237
+ try {
238
+ let response = await this.apiService.request(url, {
239
+ method: 'GET',
240
+ headers: {
241
+ 'X-Organization': organizationSlug
242
+ }
243
+ });
244
+ return response.builds || [];
245
+ } catch {
246
+ return [];
247
+ }
248
+ }
249
+
250
+ // No authentication available
251
+ return [];
171
252
  }
172
253
 
173
254
  /**
@@ -4,32 +4,32 @@
4
4
  */
5
5
 
6
6
  import { createServer } from 'http';
7
- import { BaseService } from './base-service.js';
8
7
  import { VizzlyError } from '../errors/vizzly-error.js';
9
- export class ScreenshotServer extends BaseService {
10
- constructor(config, logger, buildManager) {
11
- super(config, logger);
8
+ import * as output from '../utils/output.js';
9
+ export class ScreenshotServer {
10
+ constructor(config, buildManager) {
11
+ this.config = config;
12
12
  this.buildManager = buildManager;
13
13
  this.server = null;
14
14
  }
15
- async onStart() {
15
+ async start() {
16
16
  this.server = createServer(this.handleRequest.bind(this));
17
17
  return new Promise((resolve, reject) => {
18
18
  this.server.listen(this.config.server.port, '127.0.0.1', error => {
19
19
  if (error) {
20
20
  reject(new VizzlyError(`Failed to start screenshot server: ${error.message}`, 'SERVER_ERROR'));
21
21
  } else {
22
- this.logger.info(`Screenshot server listening on http://127.0.0.1:${this.config.server.port}`);
22
+ output.info(`Screenshot server listening on http://127.0.0.1:${this.config.server.port}`);
23
23
  resolve();
24
24
  }
25
25
  });
26
26
  });
27
27
  }
28
- async onStop() {
28
+ async stop() {
29
29
  if (this.server) {
30
30
  return new Promise(resolve => {
31
31
  this.server.close(() => {
32
- this.logger.info('Screenshot server stopped');
32
+ output.info('Screenshot server stopped');
33
33
  resolve();
34
34
  });
35
35
  });
@@ -65,7 +65,7 @@ export class ScreenshotServer extends BaseService {
65
65
  success: true
66
66
  }));
67
67
  } catch (error) {
68
- this.logger.error('Failed to process screenshot:', error);
68
+ output.error('Failed to process screenshot:', error);
69
69
  res.statusCode = 500;
70
70
  res.end(JSON.stringify({
71
71
  error: 'Internal server error'
@@ -3,15 +3,14 @@
3
3
  * Manages the HTTP server with functional handlers
4
4
  */
5
5
 
6
- import { BaseService } from './base-service.js';
7
6
  import { createHttpServer } from '../server/http-server.js';
8
7
  import { createTddHandler } from '../server/handlers/tdd-handler.js';
9
8
  import { createApiHandler } from '../server/handlers/api-handler.js';
10
9
  import { writeFileSync, mkdirSync } from 'fs';
11
10
  import { join } from 'path';
12
- export class ServerManager extends BaseService {
11
+ export class ServerManager {
13
12
  constructor(config, options = {}) {
14
- super(config, options);
13
+ this.config = config;
15
14
  this.httpServer = null;
16
15
  this.handler = null;
17
16
  this.services = options.services || {};
@@ -20,9 +19,6 @@ export class ServerManager extends BaseService {
20
19
  this.buildId = buildId;
21
20
  this.tddMode = tddMode;
22
21
  this.setBaseline = setBaseline;
23
- return super.start();
24
- }
25
- async onStart() {
26
22
  const port = this.config?.server?.port || 47392;
27
23
  if (this.tddMode) {
28
24
  this.handler = createTddHandler(this.config, process.cwd(), this.config?.baselineBuildId, this.config?.baselineComparisonId, this.setBaseline);
@@ -32,12 +28,14 @@ export class ServerManager extends BaseService {
32
28
  this.handler = createApiHandler(apiService);
33
29
  }
34
30
 
35
- // Pass buildId in services so http-server can use it as default
36
- const servicesWithBuildId = {
31
+ // Pass buildId and tddService in services so http-server can use them
32
+ const servicesWithExtras = {
37
33
  ...this.services,
38
- buildId: this.buildId
34
+ buildId: this.buildId,
35
+ // Expose tddService for baseline download operations (TDD mode only)
36
+ tddService: this.tddMode ? this.handler.tddService : null
39
37
  };
40
- this.httpServer = createHttpServer(port, this.handler, servicesWithBuildId);
38
+ this.httpServer = createHttpServer(port, this.handler, servicesWithExtras);
41
39
  if (this.httpServer) {
42
40
  await this.httpServer.start();
43
41
  }
@@ -62,10 +60,8 @@ export class ServerManager extends BaseService {
62
60
  serverInfo.buildId = this.buildId;
63
61
  }
64
62
  writeFileSync(serverFile, JSON.stringify(serverInfo, null, 2));
65
- this.logger.debug(`Wrote server info to ${serverFile}`);
66
- } catch (error) {
63
+ } catch {
67
64
  // Non-fatal - SDK can still use health check or environment variables
68
- this.logger.debug(`Failed to write server.json: ${error.message}`);
69
65
  }
70
66
  }
71
67
  async createApiService() {
@@ -76,19 +72,16 @@ export class ServerManager extends BaseService {
76
72
  return new ApiService({
77
73
  ...this.config,
78
74
  command: 'run'
79
- }, {
80
- logger: this.logger
81
75
  });
82
76
  }
83
- async onStop() {
77
+ async stop() {
84
78
  if (this.httpServer) {
85
79
  await this.httpServer.stop();
86
80
  }
87
81
  if (this.handler?.cleanup) {
88
82
  try {
89
83
  this.handler.cleanup();
90
- } catch (error) {
91
- this.logger.debug('Handler cleanup error:', error.message);
84
+ } catch {
92
85
  // Don't throw - cleanup errors shouldn't fail the stop process
93
86
  }
94
87
  }
@@ -7,8 +7,7 @@ import { writeFile, mkdir, copyFile } from 'fs/promises';
7
7
  import { existsSync } from 'fs';
8
8
  import { join, dirname } from 'path';
9
9
  import { fileURLToPath } from 'url';
10
- import { createServiceLogger } from '../utils/logger-factory.js';
11
- const logger = createServiceLogger('STATIC-REPORT');
10
+ import * as output from '../utils/output.js';
12
11
  let __filename = fileURLToPath(import.meta.url);
13
12
  let __dirname = dirname(__filename);
14
13
  let PROJECT_ROOT = join(__dirname, '..', '..');
@@ -49,10 +48,10 @@ export class StaticReportGenerator {
49
48
  // Generate HTML with embedded data
50
49
  let htmlContent = this.generateHtmlTemplate(reportData);
51
50
  await writeFile(this.reportPath, htmlContent, 'utf8');
52
- logger.debug(`Static report generated: ${this.reportPath}`);
51
+ output.debug('report', 'generated static report');
53
52
  return this.reportPath;
54
53
  } catch (error) {
55
- logger.error(`Failed to generate static report: ${error.message}`);
54
+ output.error(`Failed to generate static report: ${error.message}`);
56
55
  throw new Error(`Report generation failed: ${error.message}`);
57
56
  }
58
57
  }