@cpretzinger/boss-claude 1.0.0 → 1.0.2

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 (87) hide show
  1. package/README.md +304 -1
  2. package/bin/boss-claude.js +1138 -0
  3. package/bin/commands/mode.js +250 -0
  4. package/bin/onyx-guard.js +259 -0
  5. package/bin/onyx-guard.sh +251 -0
  6. package/bin/prompts.js +284 -0
  7. package/bin/rollback.js +85 -0
  8. package/bin/setup-wizard.js +492 -0
  9. package/config/.env.example +17 -0
  10. package/lib/README.md +83 -0
  11. package/lib/agent-logger.js +61 -0
  12. package/lib/agents/memory-engineers/github-memory-engineer.js +251 -0
  13. package/lib/agents/memory-engineers/postgres-memory-engineer.js +633 -0
  14. package/lib/agents/memory-engineers/qdrant-memory-engineer.js +358 -0
  15. package/lib/agents/memory-engineers/redis-memory-engineer.js +383 -0
  16. package/lib/agents/memory-supervisor.js +526 -0
  17. package/lib/agents/registry.js +135 -0
  18. package/lib/auto-monitor.js +131 -0
  19. package/lib/checkpoint-hook.js +112 -0
  20. package/lib/checkpoint.js +319 -0
  21. package/lib/commentator.js +213 -0
  22. package/lib/context-scribe.js +120 -0
  23. package/lib/delegation-strategies.js +326 -0
  24. package/lib/hierarchy-validator.js +643 -0
  25. package/lib/index.js +15 -0
  26. package/lib/init-with-mode.js +261 -0
  27. package/lib/init.js +44 -6
  28. package/lib/memory-result-aggregator.js +252 -0
  29. package/lib/memory.js +35 -7
  30. package/lib/mode-enforcer.js +473 -0
  31. package/lib/onyx-banner.js +169 -0
  32. package/lib/onyx-identity.js +214 -0
  33. package/lib/onyx-monitor.js +381 -0
  34. package/lib/onyx-reminder.js +188 -0
  35. package/lib/onyx-tool-interceptor.js +341 -0
  36. package/lib/onyx-wrapper.js +315 -0
  37. package/lib/orchestrator-gate.js +334 -0
  38. package/lib/output-formatter.js +296 -0
  39. package/lib/postgres.js +1 -1
  40. package/lib/prompt-injector.js +220 -0
  41. package/lib/prompts.js +532 -0
  42. package/lib/session.js +153 -6
  43. package/lib/setup/README.md +187 -0
  44. package/lib/setup/env-manager.js +785 -0
  45. package/lib/setup/error-recovery.js +630 -0
  46. package/lib/setup/explain-scopes.js +385 -0
  47. package/lib/setup/github-instructions.js +333 -0
  48. package/lib/setup/github-repo.js +254 -0
  49. package/lib/setup/import-credentials.js +498 -0
  50. package/lib/setup/index.js +62 -0
  51. package/lib/setup/init-postgres.js +785 -0
  52. package/lib/setup/init-redis.js +456 -0
  53. package/lib/setup/integration-test.js +652 -0
  54. package/lib/setup/progress.js +357 -0
  55. package/lib/setup/rollback.js +670 -0
  56. package/lib/setup/rollback.test.js +452 -0
  57. package/lib/setup/setup-with-rollback.example.js +351 -0
  58. package/lib/setup/summary.js +400 -0
  59. package/lib/setup/test-github-setup.js +10 -0
  60. package/lib/setup/test-postgres-init.js +98 -0
  61. package/lib/setup/verify-setup.js +102 -0
  62. package/lib/task-agent-worker.js +235 -0
  63. package/lib/token-monitor.js +466 -0
  64. package/lib/tool-wrapper-integration.js +369 -0
  65. package/lib/tool-wrapper.js +387 -0
  66. package/lib/validators/README.md +497 -0
  67. package/lib/validators/config.js +583 -0
  68. package/lib/validators/config.test.js +175 -0
  69. package/lib/validators/github.js +310 -0
  70. package/lib/validators/github.test.js +61 -0
  71. package/lib/validators/index.js +15 -0
  72. package/lib/validators/postgres.js +525 -0
  73. package/package.json +98 -13
  74. package/scripts/benchmark-memory.js +433 -0
  75. package/scripts/check-secrets.sh +12 -0
  76. package/scripts/fetch-todos.mjs +148 -0
  77. package/scripts/graceful-shutdown.sh +156 -0
  78. package/scripts/install-onyx-hooks.js +373 -0
  79. package/scripts/install.js +119 -18
  80. package/scripts/redis-monitor.js +284 -0
  81. package/scripts/redis-setup.js +412 -0
  82. package/scripts/test-memory-retrieval.js +201 -0
  83. package/scripts/validate-exports.js +68 -0
  84. package/scripts/validate-package.js +120 -0
  85. package/scripts/verify-onyx-deployment.js +309 -0
  86. package/scripts/verify-redis-deployment.js +354 -0
  87. package/scripts/verify-redis-init.js +219 -0
@@ -0,0 +1,652 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Boss Claude - Integration Test
4
+ *
5
+ * Validates entire system end-to-end:
6
+ * 1. Redis connectivity and operations
7
+ * 2. PostgreSQL connectivity and queries
8
+ * 3. GitHub API integration
9
+ * 4. Environment configuration
10
+ *
11
+ * Usage: node lib/setup/integration-test.js
12
+ * Or: boss-claude test
13
+ */
14
+
15
+ import chalk from 'chalk';
16
+ import ora from 'ora';
17
+ import Redis from 'ioredis';
18
+ import dotenv from 'dotenv';
19
+ import { existsSync } from 'fs';
20
+ import { join } from 'path';
21
+ import os from 'os';
22
+ import { Octokit } from '@octokit/rest';
23
+ import postgres from '../postgres.js';
24
+
25
+ // Load environment
26
+ const envPath = join(os.homedir(), '.boss-claude', '.env');
27
+ if (existsSync(envPath)) {
28
+ dotenv.config({ path: envPath });
29
+ }
30
+
31
+ // Test results tracker
32
+ const results = {
33
+ passed: 0,
34
+ failed: 0,
35
+ warnings: 0,
36
+ tests: []
37
+ };
38
+
39
+ // Helper functions
40
+ function success(message) {
41
+ console.log(chalk.green('✓'), message);
42
+ results.passed++;
43
+ }
44
+
45
+ function fail(message, error) {
46
+ console.log(chalk.red('✗'), message);
47
+ if (error) {
48
+ console.log(chalk.red(' Error:'), error.message);
49
+ }
50
+ results.failed++;
51
+ }
52
+
53
+ function warning(message) {
54
+ console.log(chalk.yellow('⚠'), message);
55
+ results.warnings++;
56
+ }
57
+
58
+ function info(message) {
59
+ console.log(chalk.blue('ℹ'), message);
60
+ }
61
+
62
+ function section(title) {
63
+ console.log('\n' + chalk.bold.cyan(`━━━ ${title} ━━━`));
64
+ }
65
+
66
+ function subsection(title) {
67
+ console.log(chalk.bold.white(`\n${title}:`));
68
+ }
69
+
70
+ // Test implementations
71
+ async function testEnvironmentVariables() {
72
+ section('Environment Configuration');
73
+
74
+ const requiredVars = [
75
+ { key: 'REDIS_URL', description: 'Redis connection string' },
76
+ { key: 'BOSS_CLAUDE_PG_URL', description: 'PostgreSQL connection string' },
77
+ { key: 'GITHUB_TOKEN', description: 'GitHub API token' }
78
+ ];
79
+
80
+ const optionalVars = [
81
+ { key: 'GITHUB_OWNER', description: 'GitHub username' },
82
+ { key: 'GITHUB_MEMORY_REPO', description: 'Memory repository name' }
83
+ ];
84
+
85
+ subsection('Required Variables');
86
+ for (const { key, description } of requiredVars) {
87
+ if (process.env[key]) {
88
+ const maskedValue = key.includes('TOKEN') || key.includes('PASSWORD') || key.includes('URL')
89
+ ? '***' + process.env[key].slice(-4)
90
+ : process.env[key];
91
+ success(`${key} (${description}): ${maskedValue}`);
92
+ } else {
93
+ fail(`${key} (${description}): NOT SET`);
94
+ }
95
+ }
96
+
97
+ subsection('Optional Variables');
98
+ for (const { key, description } of optionalVars) {
99
+ if (process.env[key]) {
100
+ success(`${key} (${description}): ${process.env[key]}`);
101
+ } else {
102
+ warning(`${key} (${description}): Not set (using defaults)`);
103
+ }
104
+ }
105
+
106
+ // Check .env file location
107
+ if (existsSync(envPath)) {
108
+ success(`Config file: ${envPath}`);
109
+ } else {
110
+ fail(`Config file not found: ${envPath}`);
111
+ }
112
+ }
113
+
114
+ async function testRedisConnection() {
115
+ section('Redis Connection & Operations');
116
+
117
+ let redis = null;
118
+ const testKey = `boss:test:${Date.now()}`;
119
+ const testValue = JSON.stringify({ test: true, timestamp: Date.now() });
120
+
121
+ try {
122
+ subsection('Connection Test');
123
+ const spinner = ora('Connecting to Redis...').start();
124
+
125
+ redis = new Redis(process.env.REDIS_URL);
126
+
127
+ // Wait for connection with timeout
128
+ await Promise.race([
129
+ new Promise((resolve) => redis.once('ready', resolve)),
130
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Connection timeout')), 5000))
131
+ ]);
132
+
133
+ spinner.succeed('Connected to Redis');
134
+ success('Redis connection established');
135
+
136
+ // Get server info
137
+ const info = await redis.info('server');
138
+ const versionMatch = info.match(/redis_version:([^\r\n]+)/);
139
+ if (versionMatch) {
140
+ success(`Redis version: ${versionMatch[1]}`);
141
+ }
142
+
143
+ subsection('Write Operations');
144
+
145
+ // Test SET
146
+ const setResult = await redis.set(testKey, testValue);
147
+ if (setResult === 'OK') {
148
+ success('SET operation successful');
149
+ } else {
150
+ fail('SET operation failed', new Error(`Unexpected result: ${setResult}`));
151
+ }
152
+
153
+ // Test TTL
154
+ const ttlResult = await redis.expire(testKey, 60);
155
+ if (ttlResult === 1) {
156
+ success('TTL set successfully (60 seconds)');
157
+ } else {
158
+ fail('TTL operation failed');
159
+ }
160
+
161
+ subsection('Read Operations');
162
+
163
+ // Test GET
164
+ const getValue = await redis.get(testKey);
165
+ if (getValue === testValue) {
166
+ success('GET operation successful');
167
+ } else {
168
+ fail('GET operation failed', new Error('Value mismatch'));
169
+ }
170
+
171
+ // Test EXISTS
172
+ const existsResult = await redis.exists(testKey);
173
+ if (existsResult === 1) {
174
+ success('EXISTS operation successful');
175
+ } else {
176
+ fail('EXISTS operation failed');
177
+ }
178
+
179
+ subsection('Boss Claude Identity Test');
180
+
181
+ // Test Boss identity operations
182
+ const identityKey = 'boss:identity:test';
183
+ const identityData = {
184
+ level: 1,
185
+ xp: 50,
186
+ token_bank: 1000,
187
+ total_sessions: 5,
188
+ repos_managed: 3,
189
+ created_at: new Date().toISOString()
190
+ };
191
+
192
+ await redis.set(identityKey, JSON.stringify(identityData));
193
+ const retrievedIdentity = await redis.get(identityKey);
194
+ const parsedIdentity = JSON.parse(retrievedIdentity);
195
+
196
+ if (parsedIdentity.level === 1 && parsedIdentity.xp === 50) {
197
+ success('Identity data serialization working correctly');
198
+ } else {
199
+ fail('Identity data mismatch');
200
+ }
201
+
202
+ subsection('Cleanup');
203
+
204
+ // Clean up test keys
205
+ await redis.del(testKey, identityKey);
206
+ success('Test keys cleaned up');
207
+
208
+ } catch (error) {
209
+ fail('Redis test failed', error);
210
+ } finally {
211
+ if (redis) {
212
+ await redis.quit();
213
+ info('Redis connection closed');
214
+ }
215
+ }
216
+ }
217
+
218
+ async function testPostgreSQLConnection() {
219
+ section('PostgreSQL Connection & Operations');
220
+
221
+ try {
222
+ subsection('Connection Test');
223
+ const spinner = ora('Testing PostgreSQL connection...').start();
224
+
225
+ const connectionTest = await postgres.utils.testConnection();
226
+
227
+ if (connectionTest.connected) {
228
+ spinner.succeed('Connected to PostgreSQL');
229
+ success('PostgreSQL connection established');
230
+
231
+ const versionParts = connectionTest.version.split(' ');
232
+ success(`PostgreSQL version: ${versionParts[1]}`);
233
+ success(`Server time: ${connectionTest.timestamp.toISOString()}`);
234
+ } else {
235
+ spinner.fail('PostgreSQL connection failed');
236
+ fail('PostgreSQL connection failed', new Error(connectionTest.error));
237
+ return; // Skip remaining tests
238
+ }
239
+
240
+ subsection('Schema Validation');
241
+
242
+ // Test schema existence
243
+ const schemaQuery = `
244
+ SELECT schema_name
245
+ FROM information_schema.schemata
246
+ WHERE schema_name = 'boss_claude'
247
+ `;
248
+ const schemaResult = await postgres.pool.query(schemaQuery);
249
+
250
+ if (schemaResult.rows.length > 0) {
251
+ success('boss_claude schema exists');
252
+ } else {
253
+ fail('boss_claude schema not found');
254
+ warning('Run database setup: boss-claude setup-db');
255
+ return; // Skip table tests
256
+ }
257
+
258
+ subsection('Table Validation');
259
+
260
+ const tables = ['sessions', 'achievements', 'memory_snapshots'];
261
+
262
+ for (const table of tables) {
263
+ const tableQuery = `
264
+ SELECT table_name
265
+ FROM information_schema.tables
266
+ WHERE table_schema = 'boss_claude'
267
+ AND table_name = $1
268
+ `;
269
+ const tableResult = await postgres.pool.query(tableQuery, [table]);
270
+
271
+ if (tableResult.rows.length > 0) {
272
+ success(`Table boss_claude.${table} exists`);
273
+ } else {
274
+ fail(`Table boss_claude.${table} not found`);
275
+ }
276
+ }
277
+
278
+ subsection('Function Validation');
279
+
280
+ const functions = [
281
+ 'fn_get_current_session',
282
+ 'fn_get_user_stats'
283
+ ];
284
+
285
+ for (const func of functions) {
286
+ const funcQuery = `
287
+ SELECT routine_name
288
+ FROM information_schema.routines
289
+ WHERE routine_schema = 'boss_claude'
290
+ AND routine_name = $1
291
+ `;
292
+ const funcResult = await postgres.pool.query(funcQuery, [func]);
293
+
294
+ if (funcResult.rows.length > 0) {
295
+ success(`Function boss_claude.${func} exists`);
296
+ } else {
297
+ warning(`Function boss_claude.${func} not found`);
298
+ }
299
+ }
300
+
301
+ subsection('Test Session Operations');
302
+
303
+ const testUserId = `test-user-${Date.now()}`;
304
+ const testProject = 'integration-test';
305
+
306
+ try {
307
+ // Create test session
308
+ const session = await postgres.sessions.start(
309
+ testUserId,
310
+ testProject,
311
+ 1,
312
+ { test: true, timestamp: Date.now() }
313
+ );
314
+
315
+ if (session && session.id) {
316
+ success(`Created test session: ${session.id}`);
317
+
318
+ // Update session
319
+ const updated = await postgres.sessions.updateProgress(session.id, {
320
+ xpEarned: 100,
321
+ tokensSaved: 500,
322
+ tasksCompleted: 5,
323
+ perfectExecutions: 2,
324
+ efficiency: 1.5
325
+ });
326
+
327
+ if (updated.xp_earned === 100 && updated.tokens_saved === 500) {
328
+ success('Session progress update successful');
329
+ } else {
330
+ fail('Session progress update failed');
331
+ }
332
+
333
+ // End session
334
+ const ended = await postgres.sessions.end(
335
+ session.id,
336
+ 2,
337
+ 'Integration test completed successfully'
338
+ );
339
+
340
+ if (ended.end_time) {
341
+ success('Session ended successfully');
342
+ } else {
343
+ fail('Session end failed');
344
+ }
345
+
346
+ // Cleanup: Delete test session
347
+ await postgres.pool.query(
348
+ 'DELETE FROM boss_claude.sessions WHERE user_id = $1',
349
+ [testUserId]
350
+ );
351
+ success('Test session cleaned up');
352
+
353
+ } else {
354
+ fail('Failed to create test session');
355
+ }
356
+ } catch (error) {
357
+ fail('Session operations failed', error);
358
+ }
359
+
360
+ } catch (error) {
361
+ fail('PostgreSQL test failed', error);
362
+ }
363
+ }
364
+
365
+ async function testGitHubIntegration() {
366
+ section('GitHub API Integration');
367
+
368
+ try {
369
+ if (!process.env.GITHUB_TOKEN) {
370
+ fail('GITHUB_TOKEN not set - skipping GitHub tests');
371
+ return;
372
+ }
373
+
374
+ subsection('Authentication Test');
375
+ const spinner = ora('Testing GitHub authentication...').start();
376
+
377
+ const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
378
+
379
+ // Test authentication by fetching user info
380
+ const { data: user } = await octokit.users.getAuthenticated();
381
+
382
+ spinner.succeed('GitHub authentication successful');
383
+ success(`Authenticated as: ${user.login}`);
384
+ success(`Account type: ${user.type}`);
385
+
386
+ subsection('Repository Access');
387
+
388
+ const owner = process.env.GITHUB_OWNER || user.login;
389
+ const repo = process.env.GITHUB_MEMORY_REPO || 'boss-claude-memory';
390
+
391
+ try {
392
+ // Check if memory repo exists
393
+ const { data: repoData } = await octokit.repos.get({ owner, repo });
394
+
395
+ success(`Memory repository accessible: ${owner}/${repo}`);
396
+ success(`Repository visibility: ${repoData.private ? 'Private' : 'Public'}`);
397
+
398
+ // Check permissions
399
+ const permissions = repoData.permissions || {};
400
+ const hasIssues = repoData.has_issues;
401
+
402
+ if (permissions.push || permissions.admin) {
403
+ success('Write permissions: YES');
404
+ } else {
405
+ warning('Write permissions: NO - may not be able to create issues');
406
+ }
407
+
408
+ if (hasIssues) {
409
+ success('Issues enabled: YES');
410
+ } else {
411
+ fail('Issues not enabled - required for memory storage');
412
+ }
413
+
414
+ subsection('Issue Operations Test');
415
+
416
+ // Create a test issue
417
+ const testIssue = await octokit.issues.create({
418
+ owner,
419
+ repo,
420
+ title: `[integration-test] Test Issue ${Date.now()}`,
421
+ body: '## Test Issue\n\nThis is an automated test issue created by Boss Claude integration tests.\n\n**Status:** Will be automatically closed.',
422
+ labels: ['test', 'automated']
423
+ });
424
+
425
+ if (testIssue.data.number) {
426
+ success(`Created test issue #${testIssue.data.number}`);
427
+
428
+ // Close the test issue
429
+ await octokit.issues.update({
430
+ owner,
431
+ repo,
432
+ issue_number: testIssue.data.number,
433
+ state: 'closed'
434
+ });
435
+
436
+ success(`Closed test issue #${testIssue.data.number}`);
437
+ } else {
438
+ fail('Failed to create test issue');
439
+ }
440
+
441
+ } catch (error) {
442
+ if (error.status === 404) {
443
+ warning(`Memory repository not found: ${owner}/${repo}`);
444
+ info(`Create it with: boss-claude setup`);
445
+ } else {
446
+ fail('Repository access test failed', error);
447
+ }
448
+ }
449
+
450
+ subsection('API Rate Limits');
451
+
452
+ const { data: rateLimit } = await octokit.rateLimit.get();
453
+ const { core } = rateLimit.resources;
454
+
455
+ const remaining = core.remaining;
456
+ const limit = core.limit;
457
+ const resetTime = new Date(core.reset * 1000);
458
+
459
+ success(`Rate limit: ${remaining}/${limit} requests remaining`);
460
+ info(`Resets at: ${resetTime.toLocaleTimeString()}`);
461
+
462
+ if (remaining < 100) {
463
+ warning('Low API rate limit remaining');
464
+ }
465
+
466
+ } catch (error) {
467
+ fail('GitHub integration test failed', error);
468
+ }
469
+ }
470
+
471
+ async function testSystemIntegration() {
472
+ section('Full System Integration');
473
+
474
+ subsection('End-to-End Workflow Test');
475
+
476
+ const testData = {
477
+ userId: `test-user-${Date.now()}`,
478
+ project: 'integration-test-e2e',
479
+ repo: 'test-repo'
480
+ };
481
+
482
+ let redis = null;
483
+ let sessionId = null;
484
+
485
+ try {
486
+ // Step 1: Redis - Store identity
487
+ info('Step 1: Creating identity in Redis...');
488
+ redis = new Redis(process.env.REDIS_URL);
489
+
490
+ const identityKey = `boss:identity:${testData.userId}`;
491
+ const identity = {
492
+ level: 1,
493
+ xp: 0,
494
+ token_bank: 0,
495
+ total_sessions: 0,
496
+ repos_managed: 1,
497
+ created_at: new Date().toISOString()
498
+ };
499
+
500
+ await redis.set(identityKey, JSON.stringify(identity));
501
+ success('Identity stored in Redis');
502
+
503
+ // Step 2: PostgreSQL - Create session
504
+ info('Step 2: Creating session in PostgreSQL...');
505
+ const session = await postgres.sessions.start(
506
+ testData.userId,
507
+ testData.project,
508
+ identity.level,
509
+ { test: true, workflow: 'e2e' }
510
+ );
511
+
512
+ sessionId = session.id;
513
+ success(`Session created: ${sessionId}`);
514
+
515
+ // Step 3: Update session with progress
516
+ info('Step 3: Recording session progress...');
517
+ await postgres.sessions.updateProgress(sessionId, {
518
+ xpEarned: 150,
519
+ tokensSaved: 1000,
520
+ tasksCompleted: 3,
521
+ perfectExecutions: 2
522
+ });
523
+ success('Session progress recorded');
524
+
525
+ // Step 4: Update identity in Redis
526
+ info('Step 4: Updating identity in Redis...');
527
+ identity.xp += 150;
528
+ identity.token_bank += 1000;
529
+ identity.total_sessions += 1;
530
+
531
+ await redis.set(identityKey, JSON.stringify(identity));
532
+ success('Identity updated in Redis');
533
+
534
+ // Step 5: End session
535
+ info('Step 5: Ending session...');
536
+ await postgres.sessions.end(
537
+ sessionId,
538
+ identity.level,
539
+ 'Integration test completed - all systems operational'
540
+ );
541
+ success('Session ended successfully');
542
+
543
+ // Step 6: Verify data consistency
544
+ info('Step 6: Verifying data consistency...');
545
+
546
+ const storedIdentity = JSON.parse(await redis.get(identityKey));
547
+ const sessionRecord = await postgres.pool.query(
548
+ 'SELECT * FROM boss_claude.sessions WHERE id = $1',
549
+ [sessionId]
550
+ );
551
+
552
+ if (storedIdentity.xp === 150 && sessionRecord.rows[0].xp_earned === 150) {
553
+ success('Data consistency verified across Redis and PostgreSQL');
554
+ } else {
555
+ fail('Data inconsistency detected');
556
+ }
557
+
558
+ // Cleanup
559
+ info('Cleaning up test data...');
560
+ await redis.del(identityKey);
561
+ await postgres.pool.query(
562
+ 'DELETE FROM boss_claude.sessions WHERE user_id = $1',
563
+ [testData.userId]
564
+ );
565
+ success('Test data cleaned up');
566
+
567
+ subsection('Integration Test Summary');
568
+ success('Full end-to-end workflow completed successfully');
569
+ success('All systems are properly integrated and operational');
570
+
571
+ } catch (error) {
572
+ fail('System integration test failed', error);
573
+ } finally {
574
+ if (redis) {
575
+ await redis.quit();
576
+ }
577
+ }
578
+ }
579
+
580
+ function printSummary() {
581
+ console.log('\n' + chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
582
+ console.log(chalk.bold.white('INTEGRATION TEST SUMMARY'));
583
+ console.log(chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
584
+
585
+ console.log(chalk.green('Passed: '), results.passed);
586
+ console.log(chalk.red('Failed: '), results.failed);
587
+ console.log(chalk.yellow('Warnings:'), results.warnings);
588
+ console.log(chalk.white('Total: '), results.passed + results.failed);
589
+
590
+ const passRate = Math.round((results.passed / (results.passed + results.failed)) * 100);
591
+
592
+ console.log('\n' + chalk.bold.white('Pass Rate:'),
593
+ passRate >= 90 ? chalk.green(`${passRate}%`) :
594
+ passRate >= 70 ? chalk.yellow(`${passRate}%`) :
595
+ chalk.red(`${passRate}%`)
596
+ );
597
+
598
+ if (results.failed === 0) {
599
+ console.log('\n' + chalk.bold.green('✓ ALL TESTS PASSED - System is fully operational!'));
600
+ } else if (results.failed < 5) {
601
+ console.log('\n' + chalk.bold.yellow('⚠ Some tests failed - System partially operational'));
602
+ } else {
603
+ console.log('\n' + chalk.bold.red('✗ Multiple failures detected - System needs attention'));
604
+ }
605
+
606
+ console.log('\n' + chalk.bold.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
607
+
608
+ // Exit with appropriate code
609
+ process.exit(results.failed > 0 ? 1 : 0);
610
+ }
611
+
612
+ // Main execution
613
+ async function runIntegrationTests() {
614
+ console.log(chalk.bold.cyan('\n╔══════════════════════════════════════════════╗'));
615
+ console.log(chalk.bold.cyan('║ BOSS CLAUDE - INTEGRATION TEST SUITE ║'));
616
+ console.log(chalk.bold.cyan('╚══════════════════════════════════════════════╝\n'));
617
+
618
+ info('Testing complete system integration...');
619
+ info(`Environment: ${envPath}\n`);
620
+
621
+ try {
622
+ // Run all test suites
623
+ await testEnvironmentVariables();
624
+ await testRedisConnection();
625
+ await testPostgreSQLConnection();
626
+ await testGitHubIntegration();
627
+ await testSystemIntegration();
628
+
629
+ // Print final summary
630
+ printSummary();
631
+
632
+ } catch (error) {
633
+ console.error(chalk.red('\n✗ Fatal error during integration tests:'));
634
+ console.error(chalk.red(error.message));
635
+ console.error(error.stack);
636
+ process.exit(1);
637
+ }
638
+ }
639
+
640
+ // Run tests if executed directly
641
+ if (import.meta.url === `file://${process.argv[1]}`) {
642
+ runIntegrationTests();
643
+ }
644
+
645
+ export {
646
+ runIntegrationTests,
647
+ testEnvironmentVariables,
648
+ testRedisConnection,
649
+ testPostgreSQLConnection,
650
+ testGitHubIntegration,
651
+ testSystemIntegration
652
+ };