@wundr.io/cli 1.0.1 → 1.0.2-dev.20260530174250.ef0ec927

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 (69) hide show
  1. package/bin/wundr.js +13 -5
  2. package/package.json +30 -9
  3. package/src/ai/ai-service.ts +6 -4
  4. package/src/ai/claude-client.ts +6 -2
  5. package/src/ai/conversation-manager.ts +12 -5
  6. package/src/cli.ts +42 -13
  7. package/src/commands/ai.ts +340 -64
  8. package/src/commands/alignment.ts +1212 -0
  9. package/src/commands/analyze-optimized.ts +371 -33
  10. package/src/commands/analyze.ts +8 -6
  11. package/src/commands/batch.ts +166 -26
  12. package/src/commands/chat.ts +20 -10
  13. package/src/commands/claude-init.ts +31 -27
  14. package/src/commands/claude-setup.ts +761 -81
  15. package/src/commands/computer-setup.ts +524 -12
  16. package/src/commands/create-command.ts +3 -3
  17. package/src/commands/create.ts +9 -6
  18. package/src/commands/dashboard.ts +11 -6
  19. package/src/commands/govern.ts +11 -6
  20. package/src/commands/governance.ts +1005 -0
  21. package/src/commands/guardian.ts +887 -0
  22. package/src/commands/init.ts +104 -11
  23. package/src/commands/orchestrator.ts +789 -0
  24. package/src/commands/performance-optimizer.ts +15 -10
  25. package/src/commands/plugins.ts +8 -5
  26. package/src/commands/project-update.ts +1156 -0
  27. package/src/commands/rag.ts +1011 -0
  28. package/src/commands/session.ts +631 -0
  29. package/src/commands/setup.ts +42 -344
  30. package/src/commands/test-init.ts +3 -2
  31. package/src/commands/test.ts +3 -2
  32. package/src/commands/watch.ts +21 -11
  33. package/src/commands/worktree.ts +1057 -0
  34. package/src/context/context-manager.ts +5 -2
  35. package/src/context/session-manager.ts +18 -7
  36. package/src/framework/command-interface.ts +520 -0
  37. package/src/framework/command-registry.ts +942 -0
  38. package/src/framework/completion-exporter.ts +383 -0
  39. package/src/framework/debug-logger.ts +519 -0
  40. package/src/framework/error-handler.ts +867 -0
  41. package/src/framework/help-generator.ts +540 -0
  42. package/src/framework/index.ts +169 -0
  43. package/src/framework/interactive-repl.ts +703 -0
  44. package/src/framework/output-formatter.ts +834 -0
  45. package/src/framework/progress-manager.ts +539 -0
  46. package/src/index.ts +3 -2
  47. package/src/interactive/interactive-mode.ts +14 -7
  48. package/src/lib/conflict-resolution.ts +818 -0
  49. package/src/lib/merge-strategy.ts +550 -0
  50. package/src/lib/safety-mechanisms.ts +451 -0
  51. package/src/lib/state-detection.ts +1030 -0
  52. package/src/nlp/command-mapper.ts +8 -3
  53. package/src/nlp/command-parser.ts +5 -2
  54. package/src/nlp/intent-parser.ts +23 -9
  55. package/src/plugins/plugin-manager.ts +50 -24
  56. package/src/tests/computer-setup-integration.test.ts +46 -15
  57. package/src/types/index.ts +1 -1
  58. package/src/types/modules.d.ts +425 -1
  59. package/src/utils/backup-rollback-manager.ts +19 -14
  60. package/src/utils/claude-config-installer.ts +119 -28
  61. package/src/utils/config-manager.ts +9 -6
  62. package/src/utils/error-handler.ts +3 -1
  63. package/src/utils/logger.ts +35 -12
  64. package/templates/batch/ci-cd.yaml +7 -7
  65. package/test-suites/api/health.spec.ts +20 -23
  66. package/test-suites/helpers/test-config.ts +14 -13
  67. package/test-suites/ui/accessibility.spec.ts +27 -22
  68. package/test-suites/ui/smoke.spec.ts +26 -21
  69. package/src/commands/computer-setup-commands.ts +0 -869
@@ -3,13 +3,15 @@
3
3
  * Handles installation of CLAUDE.md, hooks, conventions, and agent templates
4
4
  */
5
5
 
6
+ import { existsSync } from 'fs';
6
7
  import * as fs from 'fs/promises';
7
8
  import * as path from 'path';
8
- import { existsSync } from 'fs';
9
+
9
10
  import chalk from 'chalk';
10
11
  import ora from 'ora';
11
- import { logger } from './logger';
12
+
12
13
  import { BackupRollbackManager } from './backup-rollback-manager';
14
+ import { logger } from './logger';
13
15
 
14
16
  export interface ClaudeConfigOptions {
15
17
  claudeDir?: string;
@@ -55,7 +57,12 @@ export class ClaudeConfigInstaller {
55
57
  * Install all Claude Code configurations
56
58
  */
57
59
  async install(options: ClaudeConfigOptions = {}): Promise<InstallResult> {
58
- const { dryRun = false, skipBackup = false, overwrite = false, verbose = false } = options;
60
+ const {
61
+ dryRun = false,
62
+ skipBackup = false,
63
+ overwrite = false,
64
+ verbose = false,
65
+ } = options;
59
66
 
60
67
  const result: InstallResult = {
61
68
  success: false,
@@ -71,7 +78,9 @@ export class ClaudeConfigInstaller {
71
78
  if (!skipBackup && !dryRun) {
72
79
  const existingFiles = await this.getExistingConfigFiles();
73
80
  if (existingFiles.length > 0) {
74
- const spinner = ora('Creating backup of existing configurations...').start();
81
+ const spinner = ora(
82
+ 'Creating backup of existing configurations...'
83
+ ).start();
75
84
  const backup = await this.backupManager.createBackup(
76
85
  existingFiles,
77
86
  'Pre-installation backup'
@@ -94,10 +103,18 @@ export class ClaudeConfigInstaller {
94
103
  await this.installAgentTemplates(result, { dryRun, overwrite, verbose });
95
104
 
96
105
  // Install git-worktree workflows
97
- await this.installGitWorktreeWorkflows(result, { dryRun, overwrite, verbose });
106
+ await this.installGitWorktreeWorkflows(result, {
107
+ dryRun,
108
+ overwrite,
109
+ verbose,
110
+ });
98
111
 
99
112
  // Install validation scripts
100
- await this.installValidationScripts(result, { dryRun, overwrite, verbose });
113
+ await this.installValidationScripts(result, {
114
+ dryRun,
115
+ overwrite,
116
+ verbose,
117
+ });
101
118
 
102
119
  result.success = result.errors.length === 0;
103
120
 
@@ -109,7 +126,7 @@ export class ClaudeConfigInstaller {
109
126
  logger.error('Installation failed', error);
110
127
  result.errors.push({
111
128
  file: 'general',
112
- error: error instanceof Error ? error.message : String(error)
129
+ error: error instanceof Error ? error.message : String(error),
113
130
  });
114
131
  return result;
115
132
  }
@@ -157,7 +174,7 @@ export class ClaudeConfigInstaller {
157
174
  spinner.fail('Failed to install CLAUDE.md');
158
175
  result.errors.push({
159
176
  file: 'CLAUDE.md',
160
- error: error instanceof Error ? error.message : String(error)
177
+ error: error instanceof Error ? error.message : String(error),
161
178
  });
162
179
  logger.error('CLAUDE.md installation failed', error);
163
180
  }
@@ -202,7 +219,7 @@ export class ClaudeConfigInstaller {
202
219
  spinner.fail('Failed to install hooks');
203
220
  result.errors.push({
204
221
  file: 'hooks',
205
- error: error instanceof Error ? error.message : String(error)
222
+ error: error instanceof Error ? error.message : String(error),
206
223
  });
207
224
  logger.error('Hooks installation failed', error);
208
225
  }
@@ -242,7 +259,7 @@ export class ClaudeConfigInstaller {
242
259
  spinner.fail('Failed to install conventions');
243
260
  result.errors.push({
244
261
  file: 'conventions.json',
245
- error: error instanceof Error ? error.message : String(error)
262
+ error: error instanceof Error ? error.message : String(error),
246
263
  });
247
264
  logger.error('Conventions installation failed', error);
248
265
  }
@@ -264,34 +281,90 @@ export class ClaudeConfigInstaller {
264
281
  const templates = this.generateAgentTemplates();
265
282
 
266
283
  for (const [agentName, agentConfig] of Object.entries(templates)) {
267
- const agentPath = path.join(agentsDir, `${agentName}.json`);
284
+ // Generate .md files with proper YAML frontmatter (not .json)
285
+ const agentPath = path.join(agentsDir, `${agentName}.md`);
268
286
 
269
287
  if (existsSync(agentPath) && !options.overwrite) {
270
- result.skipped.push(`agents/${agentName}.json`);
288
+ result.skipped.push(`agents/${agentName}.md`);
271
289
  continue;
272
290
  }
273
291
 
274
292
  if (options.dryRun) {
275
- result.installed.push(`agents/${agentName}.json (dry-run)`);
293
+ result.installed.push(`agents/${agentName}.md (dry-run)`);
276
294
  continue;
277
295
  }
278
296
 
279
- await fs.writeFile(agentPath, JSON.stringify(agentConfig, null, 2));
280
- result.installed.push(`agents/${agentName}.json`);
297
+ // Generate markdown with YAML frontmatter
298
+ const mdContent = this.generateAgentMarkdownContent(
299
+ agentName,
300
+ agentConfig
301
+ );
302
+ await fs.writeFile(agentPath, mdContent);
303
+ result.installed.push(`agents/${agentName}.md`);
281
304
  }
282
305
 
283
- spinner.succeed(`Agent templates installed (${Object.keys(templates).length} templates)`);
284
- logger.info('Agent templates installed', { count: Object.keys(templates).length });
306
+ spinner.succeed(
307
+ `Agent templates installed (${Object.keys(templates).length} templates)`
308
+ );
309
+ logger.info('Agent templates installed', {
310
+ count: Object.keys(templates).length,
311
+ });
285
312
  } catch (error) {
286
313
  spinner.fail('Failed to install agent templates');
287
314
  result.errors.push({
288
315
  file: 'agent-templates',
289
- error: error instanceof Error ? error.message : String(error)
316
+ error: error instanceof Error ? error.message : String(error),
290
317
  });
291
318
  logger.error('Agent templates installation failed', error);
292
319
  }
293
320
  }
294
321
 
322
+ /**
323
+ * Generate markdown content with proper YAML frontmatter for agent files
324
+ */
325
+ private generateAgentMarkdownContent(
326
+ agentName: string,
327
+ config: {
328
+ name: string;
329
+ role: string;
330
+ responsibilities: string[];
331
+ tools: string[];
332
+ patterns: string[];
333
+ }
334
+ ): string {
335
+ const firstResponsibility =
336
+ config.responsibilities[0] ?? 'software development';
337
+ const description = `${config.name} specialist for ${firstResponsibility.toLowerCase()}.`;
338
+ const toolsList = 'Read, Write, Edit, Bash, Glob, Grep';
339
+ const useFor =
340
+ config.responsibilities.slice(0, 2).join(', ').toLowerCase() ||
341
+ 'development tasks';
342
+
343
+ return `---
344
+ name: ${agentName}
345
+ description: >
346
+ ${description}
347
+ Use for ${useFor}.
348
+ tools: ${toolsList}
349
+ model: sonnet
350
+ ---
351
+
352
+ # ${config.name}
353
+
354
+ ## Role
355
+ ${config.role}
356
+
357
+ ## Responsibilities
358
+ ${config.responsibilities.map(r => `- ${r}`).join('\n')}
359
+
360
+ ## Tools & Technologies
361
+ ${config.tools.map(t => `- ${t}`).join('\n')}
362
+
363
+ ## Patterns
364
+ ${config.patterns.map(p => `- ${p}`).join('\n')}
365
+ `;
366
+ }
367
+
295
368
  /**
296
369
  * Install git-worktree workflows
297
370
  */
@@ -320,17 +393,24 @@ export class ClaudeConfigInstaller {
320
393
  continue;
321
394
  }
322
395
 
323
- await fs.writeFile(workflowPath, JSON.stringify(workflowContent, null, 2));
396
+ await fs.writeFile(
397
+ workflowPath,
398
+ JSON.stringify(workflowContent, null, 2)
399
+ );
324
400
  result.installed.push(`workflows/${workflowName}.json`);
325
401
  }
326
402
 
327
- spinner.succeed(`Git-worktree workflows installed (${Object.keys(workflows).length} workflows)`);
328
- logger.info('Git-worktree workflows installed', { count: Object.keys(workflows).length });
403
+ spinner.succeed(
404
+ `Git-worktree workflows installed (${Object.keys(workflows).length} workflows)`
405
+ );
406
+ logger.info('Git-worktree workflows installed', {
407
+ count: Object.keys(workflows).length,
408
+ });
329
409
  } catch (error) {
330
410
  spinner.fail('Failed to install git-worktree workflows');
331
411
  result.errors.push({
332
412
  file: 'git-worktree-workflows',
333
- error: error instanceof Error ? error.message : String(error)
413
+ error: error instanceof Error ? error.message : String(error),
334
414
  });
335
415
  logger.error('Git-worktree workflows installation failed', error);
336
416
  }
@@ -369,13 +449,17 @@ export class ClaudeConfigInstaller {
369
449
  result.installed.push(`scripts/${scriptName}`);
370
450
  }
371
451
 
372
- spinner.succeed(`Validation scripts installed (${Object.keys(scripts).length} scripts)`);
373
- logger.info('Validation scripts installed', { count: Object.keys(scripts).length });
452
+ spinner.succeed(
453
+ `Validation scripts installed (${Object.keys(scripts).length} scripts)`
454
+ );
455
+ logger.info('Validation scripts installed', {
456
+ count: Object.keys(scripts).length,
457
+ });
374
458
  } catch (error) {
375
459
  spinner.fail('Failed to install validation scripts');
376
460
  result.errors.push({
377
461
  file: 'validation-scripts',
378
- error: error instanceof Error ? error.message : String(error)
462
+ error: error instanceof Error ? error.message : String(error),
379
463
  });
380
464
  logger.error('Validation scripts installation failed', error);
381
465
  }
@@ -571,7 +655,8 @@ echo "✅ Post-checkout completed"
571
655
  },
572
656
  'bug-fix': {
573
657
  name: 'Bug Fix Workflow',
574
- description: 'Workflow for fixing bugs without affecting main development',
658
+ description:
659
+ 'Workflow for fixing bugs without affecting main development',
575
660
  steps: [
576
661
  {
577
662
  name: 'Create worktree',
@@ -719,13 +804,19 @@ echo "✅ Configuration check complete"
719
804
  console.log(chalk.green('✅ Installation completed successfully!\n'));
720
805
  console.log(chalk.cyan('Next steps:'));
721
806
  console.log(chalk.white(' 1. Review installed configurations'));
722
- console.log(chalk.white(' 2. Run validation: ~/.claude/scripts/validate-setup.sh'));
807
+ console.log(
808
+ chalk.white(' 2. Run validation: ~/.claude/scripts/validate-setup.sh')
809
+ );
723
810
  console.log(chalk.white(' 3. Customize agent templates as needed'));
724
811
  } else {
725
812
  console.log(chalk.red('❌ Installation completed with errors\n'));
726
813
  if (result.backupId) {
727
814
  console.log(chalk.cyan('To rollback:'));
728
- console.log(chalk.white(` wundr computer-setup rollback --backup ${result.backupId}`));
815
+ console.log(
816
+ chalk.white(
817
+ ` wundr computer-setup rollback --backup ${result.backupId}`
818
+ )
819
+ );
729
820
  }
730
821
  }
731
822
  }
@@ -1,10 +1,13 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
1
  import os from 'os';
2
+ import path from 'path';
3
+
4
+ import fs from 'fs-extra';
4
5
  import { z } from 'zod';
5
- import { WundrConfig } from '../types';
6
- import { logger } from './logger';
6
+
7
7
  import { errorHandler } from './error-handler';
8
+ import { logger } from './logger';
9
+
10
+ import type { WundrConfig } from '../types';
8
11
 
9
12
  // Zod schema for configuration validation
10
13
  const WundrConfigSchema = z.object({
@@ -213,7 +216,7 @@ export class ConfigManager {
213
216
  throw new Error(`Invalid path: empty key at position ${i}`);
214
217
  }
215
218
  if (!current || typeof current !== 'object') {
216
- throw new Error(`Invalid path: cannot set property on non-object`);
219
+ throw new Error('Invalid path: cannot set property on non-object');
217
220
  }
218
221
  if (!current[key] || typeof current[key] !== 'object') {
219
222
  current[key] = {};
@@ -226,7 +229,7 @@ export class ConfigManager {
226
229
  throw new Error('Invalid path: empty final key');
227
230
  }
228
231
  if (!finalKey || !current || typeof current !== 'object') {
229
- throw new Error(`Invalid path: cannot set property`);
232
+ throw new Error('Invalid path: cannot set property');
230
233
  }
231
234
  current[finalKey] = value;
232
235
  }
@@ -1,7 +1,9 @@
1
1
  import chalk from 'chalk';
2
- import { WundrError } from '../types';
2
+
3
3
  import { logger } from './logger';
4
4
 
5
+ import type { WundrError } from '../types';
6
+
5
7
  /**
6
8
  * Centralized error handling system
7
9
  */
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
- import { Logger } from '../types';
2
+
3
+ import type { Logger } from '../types';
3
4
 
4
5
  /**
5
6
  * Enhanced logger with multiple levels and colored output
@@ -17,7 +18,9 @@ class WundrLogger implements Logger {
17
18
  }
18
19
 
19
20
  private shouldLog(level: string): boolean {
20
- if (this.silent) return false;
21
+ if (this.silent) {
22
+ return false;
23
+ }
21
24
 
22
25
  const levels = { debug: 0, info: 1, warn: 2, error: 3 };
23
26
  return levels[level as keyof typeof levels] >= levels[this.level];
@@ -36,54 +39,74 @@ class WundrLogger implements Logger {
36
39
  }
37
40
 
38
41
  debug(message: string, ...args: any[]): void {
39
- if (!this.shouldLog('debug')) return;
42
+ if (!this.shouldLog('debug')) {
43
+ return;
44
+ }
40
45
  console.log(chalk.gray(this.formatMessage('debug', message, ...args)));
41
46
  }
42
47
 
43
48
  info(message: string, ...args: any[]): void {
44
- if (!this.shouldLog('info')) return;
49
+ if (!this.shouldLog('info')) {
50
+ return;
51
+ }
45
52
  console.log(chalk.blue(this.formatMessage('info', message, ...args)));
46
53
  }
47
54
 
48
55
  warn(message: string, ...args: any[]): void {
49
- if (!this.shouldLog('warn')) return;
56
+ if (!this.shouldLog('warn')) {
57
+ return;
58
+ }
50
59
  console.warn(chalk.yellow(this.formatMessage('warn', message, ...args)));
51
60
  }
52
61
 
53
62
  error(message: string, ...args: any[]): void {
54
- if (!this.shouldLog('error')) return;
63
+ if (!this.shouldLog('error')) {
64
+ return;
65
+ }
55
66
  console.error(chalk.red(this.formatMessage('error', message, ...args)));
56
67
  }
57
68
 
58
69
  success(message: string, ...args: any[]): void {
59
- if (!this.shouldLog('info')) return;
70
+ if (!this.shouldLog('info')) {
71
+ return;
72
+ }
60
73
  console.log(chalk.green(this.formatMessage('success', message, ...args)));
61
74
  }
62
75
 
63
76
  // Utility methods for structured logging
64
77
  table(data: any[]): void {
65
- if (this.silent) return;
78
+ if (this.silent) {
79
+ return;
80
+ }
66
81
  console.table(data);
67
82
  }
68
83
 
69
84
  json(data: any): void {
70
- if (this.silent) return;
85
+ if (this.silent) {
86
+ return;
87
+ }
71
88
  console.log(JSON.stringify(data, null, 2));
72
89
  }
73
90
 
74
91
  group(label: string): void {
75
- if (this.silent) return;
92
+ if (this.silent) {
93
+ return;
94
+ }
76
95
  console.group(chalk.cyan(label));
77
96
  }
78
97
 
79
98
  groupEnd(): void {
80
- if (this.silent) return;
99
+ if (this.silent) {
100
+ return;
101
+ }
81
102
  console.groupEnd();
82
103
  }
83
104
 
84
105
  // Progress logging
85
106
  progress(current: number, total: number, message?: string): void {
86
- if (this.silent) return;
107
+ if (this.silent) {
108
+ return;
109
+ }
87
110
  const percentage = Math.round((current / total) * 100);
88
111
  const bar = '█'.repeat(Math.round(percentage / 2));
89
112
  const empty = '░'.repeat(50 - Math.round(percentage / 2));
@@ -7,7 +7,7 @@ description: Continuous Integration and Deployment pipeline
7
7
  # Global settings
8
8
  parallel: false
9
9
  continueOnError: false
10
- timeout: 1800000 # 30 minutes
10
+ timeout: 1800000 # 30 minutes
11
11
 
12
12
  # Environment variables
13
13
  variables:
@@ -23,7 +23,7 @@ commands:
23
23
  # Install dependencies
24
24
  - command: "npm ci"
25
25
  retry: 2
26
- timeout: 300000 # 5 minutes
26
+ timeout: 300000 # 5 minutes
27
27
 
28
28
  # Code quality checks
29
29
  - command: "npm run lint"
@@ -34,11 +34,11 @@ commands:
34
34
 
35
35
  # Testing
36
36
  - command: "npm run test"
37
- timeout: 600000 # 10 minutes
37
+ timeout: 600000 # 10 minutes
38
38
 
39
39
  - command: "npm run test:e2e"
40
40
  condition: "e2e-tests-exist"
41
- timeout: 900000 # 15 minutes
41
+ timeout: 900000 # 15 minutes
42
42
 
43
43
  # Security audit
44
44
  - command: "npm audit --audit-level high"
@@ -46,7 +46,7 @@ commands:
46
46
 
47
47
  # Build
48
48
  - command: "npm run build"
49
- timeout: 300000 # 5 minutes
49
+ timeout: 300000 # 5 minutes
50
50
 
51
51
  # Package
52
52
  - command: "npm pack"
@@ -55,8 +55,8 @@ commands:
55
55
  # Deploy (conditional)
56
56
  - command: "npm run deploy"
57
57
  condition: "production"
58
- timeout: 600000 # 10 minutes
58
+ timeout: 600000 # 10 minutes
59
59
 
60
60
  # Cleanup
61
61
  - command: "echo 'CI/CD pipeline completed'"
62
- condition: "always"
62
+ condition: "always"
@@ -15,11 +15,11 @@ test.describe('API Health Checks', () => {
15
15
  '/status',
16
16
  '/api/status',
17
17
  '/_health',
18
- '/ping'
18
+ '/ping',
19
19
  ];
20
20
 
21
21
  let healthyEndpoint = null;
22
-
22
+
23
23
  for (const endpoint of healthEndpoints) {
24
24
  try {
25
25
  const response = await request.get(`${baseURL}${endpoint}`);
@@ -38,23 +38,18 @@ test.describe('API Health Checks', () => {
38
38
 
39
39
  test('API returns proper content types', async ({ request, baseURL }) => {
40
40
  // Try to find an API endpoint
41
- const apiEndpoints = [
42
- '/api',
43
- '/api/v1',
44
- '/api/v2',
45
- '/graphql'
46
- ];
41
+ const apiEndpoints = ['/api', '/api/v1', '/api/v2', '/graphql'];
47
42
 
48
43
  for (const endpoint of apiEndpoints) {
49
44
  try {
50
45
  const response = await request.get(`${baseURL}${endpoint}`);
51
46
  if (response.ok() || response.status() === 404) {
52
47
  const contentType = response.headers()['content-type'];
53
-
48
+
54
49
  // Should return JSON or HTML
55
50
  expect(
56
51
  contentType?.includes('application/json') ||
57
- contentType?.includes('text/html')
52
+ contentType?.includes('text/html')
58
53
  ).toBeTruthy();
59
54
  }
60
55
  } catch {
@@ -65,11 +60,13 @@ test.describe('API Health Checks', () => {
65
60
 
66
61
  test('API handles errors gracefully', async ({ request, baseURL }) => {
67
62
  // Test 404 handling
68
- const response = await request.get(`${baseURL}/api/nonexistent-endpoint-${Date.now()}`);
69
-
63
+ const response = await request.get(
64
+ `${baseURL}/api/nonexistent-endpoint-${Date.now()}`
65
+ );
66
+
70
67
  // Should return appropriate status code
71
68
  expect([404, 400, 401, 403]).toContain(response.status());
72
-
69
+
73
70
  // Should not expose sensitive information
74
71
  const body = await response.text();
75
72
  expect(body).not.toContain('stack');
@@ -78,12 +75,12 @@ test.describe('API Health Checks', () => {
78
75
 
79
76
  test('API responds within acceptable time', async ({ request, baseURL }) => {
80
77
  const startTime = Date.now();
81
-
78
+
82
79
  // Make a simple request
83
80
  await request.get(`${baseURL}/`);
84
-
81
+
85
82
  const responseTime = Date.now() - startTime;
86
-
83
+
87
84
  // Should respond within 5 seconds
88
85
  expect(responseTime).toBeLessThan(5000);
89
86
  });
@@ -92,18 +89,18 @@ test.describe('API Health Checks', () => {
92
89
  try {
93
90
  const response = await request.get(`${baseURL}/api`, {
94
91
  headers: {
95
- 'Origin': 'https://example.com'
96
- }
92
+ Origin: 'https://example.com',
93
+ },
97
94
  });
98
95
 
99
96
  const headers = response.headers();
100
-
97
+
101
98
  // Check for CORS headers if API exists
102
99
  if (response.status() !== 404) {
103
- const hasCorsHeaders =
100
+ const hasCorsHeaders =
104
101
  headers['access-control-allow-origin'] !== undefined ||
105
102
  headers['access-control-allow-methods'] !== undefined;
106
-
103
+
107
104
  // Log CORS configuration
108
105
  console.log('CORS configured:', hasCorsHeaders);
109
106
  }
@@ -119,7 +116,7 @@ test.describe('API Health Checks', () => {
119
116
  for (const method of methods) {
120
117
  try {
121
118
  const response = await request.fetch(`${baseURL}/api`, {
122
- method
119
+ method,
123
120
  });
124
121
  results[method] = response.status();
125
122
  } catch {
@@ -131,4 +128,4 @@ test.describe('API Health Checks', () => {
131
128
  expect(results['GET']).toBeGreaterThan(0);
132
129
  expect(results['OPTIONS']).toBeGreaterThan(0);
133
130
  });
134
- });
131
+ });
@@ -12,7 +12,7 @@ export interface TestConfig {
12
12
  screenshot: 'off' | 'on' | 'only-on-failure';
13
13
  video: 'off' | 'on' | 'retain-on-failure';
14
14
  trace: 'off' | 'on' | 'on-first-retry';
15
-
15
+
16
16
  // Custom selectors for specific apps
17
17
  selectors?: {
18
18
  navigation?: string;
@@ -21,14 +21,14 @@ export interface TestConfig {
21
21
  searchInput?: string;
22
22
  loginButton?: string;
23
23
  };
24
-
24
+
25
25
  // API configuration
26
26
  api?: {
27
27
  baseURL?: string;
28
28
  headers?: Record<string, string>;
29
29
  timeout?: number;
30
30
  };
31
-
31
+
32
32
  // Test data
33
33
  testData?: {
34
34
  validUser?: {
@@ -47,18 +47,19 @@ export const defaultConfig: TestConfig = {
47
47
  screenshot: 'only-on-failure',
48
48
  video: 'retain-on-failure',
49
49
  trace: 'on-first-retry',
50
-
50
+
51
51
  selectors: {
52
52
  navigation: 'nav, [role="navigation"], header',
53
53
  mainContent: 'main, [role="main"], #content',
54
54
  footer: 'footer, [role="contentinfo"]',
55
55
  searchInput: 'input[type="search"], input[placeholder*="search" i]',
56
- loginButton: 'button[type="submit"], button:has-text("Login"), button:has-text("Sign in")'
56
+ loginButton:
57
+ 'button[type="submit"], button:has-text("Login"), button:has-text("Sign in")',
57
58
  },
58
-
59
+
59
60
  api: {
60
- timeout: 10000
61
- }
61
+ timeout: 10000,
62
+ },
62
63
  };
63
64
 
64
65
  /**
@@ -70,15 +71,15 @@ export function loadConfig(customConfig?: Partial<TestConfig>): TestConfig {
70
71
  ...customConfig,
71
72
  selectors: {
72
73
  ...defaultConfig.selectors,
73
- ...customConfig?.selectors
74
+ ...customConfig?.selectors,
74
75
  },
75
76
  api: {
76
77
  ...defaultConfig.api,
77
- ...customConfig?.api
78
+ ...customConfig?.api,
78
79
  },
79
80
  testData: {
80
81
  ...defaultConfig.testData,
81
- ...customConfig?.testData
82
- }
82
+ ...customConfig?.testData,
83
+ },
83
84
  };
84
- }
85
+ }