@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,433 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MEMORY SYSTEM BENCHMARK
5
+ *
6
+ * Compares old GitHub-based memory system vs new MemorySupervisor system
7
+ *
8
+ * Metrics:
9
+ * - Response time (target: <5s vs 120s)
10
+ * - Cache hit rate (Redis vs none)
11
+ * - Memory usage (Node.js heap)
12
+ * - Token savings at startup
13
+ * - Engineer response times (parallel vs sequential)
14
+ *
15
+ * Usage:
16
+ * node scripts/benchmark-memory.js
17
+ * node scripts/benchmark-memory.js --verbose
18
+ * node scripts/benchmark-memory.js --runs 10
19
+ */
20
+
21
+ import { searchMemory } from '../lib/memory.js';
22
+ import { queryMemorySupervisor, invalidateMemoryCache, getMemoryCacheStats, closeConnections } from '../lib/agents/memory-supervisor.js';
23
+ import { performance } from 'perf_hooks';
24
+ import { fileURLToPath } from 'url';
25
+ import { dirname } from 'path';
26
+
27
+ const __filename = fileURLToPath(import.meta.url);
28
+ const __dirname = dirname(__filename);
29
+
30
+ // Parse CLI args
31
+ const args = process.argv.slice(2);
32
+ const verbose = args.includes('--verbose') || args.includes('-v');
33
+ const runsArg = args.find(arg => arg.startsWith('--runs='));
34
+ const numberOfRuns = runsArg ? parseInt(runsArg.split('=')[1]) : 3;
35
+
36
+ // Test queries (varied complexity)
37
+ const TEST_QUERIES = [
38
+ 'postgres database schema',
39
+ 'redis cache optimization',
40
+ 'n8n workflow automation',
41
+ 'github repository setup',
42
+ 'session management',
43
+ 'memory system architecture',
44
+ 'authentication implementation',
45
+ 'api endpoint design'
46
+ ];
47
+
48
+ /**
49
+ * Get memory usage in MB
50
+ */
51
+ function getMemoryUsage() {
52
+ const usage = process.memoryUsage();
53
+ return {
54
+ heapUsed: Math.round(usage.heapUsed / 1024 / 1024),
55
+ heapTotal: Math.round(usage.heapTotal / 1024 / 1024),
56
+ rss: Math.round(usage.rss / 1024 / 1024),
57
+ external: Math.round(usage.external / 1024 / 1024)
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Benchmark OLD system (direct GitHub API)
63
+ */
64
+ async function benchmarkOldSystem(query, limit = 5) {
65
+ const startTime = performance.now();
66
+ const startMemory = getMemoryUsage();
67
+
68
+ let result = null;
69
+ let error = null;
70
+
71
+ try {
72
+ result = await searchMemory(query, limit);
73
+ } catch (err) {
74
+ error = err.message;
75
+ }
76
+
77
+ const endTime = performance.now();
78
+ const endMemory = getMemoryUsage();
79
+ const duration = endTime - startTime;
80
+
81
+ return {
82
+ system: 'old',
83
+ query,
84
+ duration_ms: Math.round(duration),
85
+ duration_s: (duration / 1000).toFixed(2),
86
+ result_count: result ? result.length : 0,
87
+ error,
88
+ cache_hit: false,
89
+ memory_delta_mb: endMemory.heapUsed - startMemory.heapUsed,
90
+ memory_used_mb: endMemory.heapUsed,
91
+ engineers_queried: 0,
92
+ source: 'github-api-direct'
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Benchmark NEW system (MemorySupervisor with 4 engineers)
98
+ */
99
+ async function benchmarkNewSystem(query, limit = 5, useCache = true) {
100
+ const startTime = performance.now();
101
+ const startMemory = getMemoryUsage();
102
+
103
+ let result = null;
104
+ let error = null;
105
+
106
+ try {
107
+ result = await queryMemorySupervisor(query, {
108
+ useCache,
109
+ timeout: 5000,
110
+ cacheTtl: 300,
111
+ limit
112
+ });
113
+ } catch (err) {
114
+ error = err.message;
115
+ }
116
+
117
+ const endTime = performance.now();
118
+ const endMemory = getMemoryUsage();
119
+ const duration = endTime - startTime;
120
+
121
+ return {
122
+ system: 'new',
123
+ query,
124
+ duration_ms: Math.round(duration),
125
+ duration_s: (duration / 1000).toFixed(2),
126
+ result_count: result ? result.total_results : 0,
127
+ error,
128
+ cache_hit: result ? result.cache_hit : false,
129
+ memory_delta_mb: endMemory.heapUsed - startMemory.heapUsed,
130
+ memory_used_mb: endMemory.heapUsed,
131
+ engineers_queried: result ? result.engineers_queried.length : 0,
132
+ engineer_details: result ? result.engineers_queried : [],
133
+ source: result && result.cache_hit ? 'redis-cache' : 'parallel-engineers',
134
+ query_time_from_response: result ? result.query_time_ms : null
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Run benchmark comparison
140
+ */
141
+ async function runBenchmark(query, runNumber, totalRuns) {
142
+ if (verbose) {
143
+ console.log(`\n[${'='.repeat(60)}]`);
144
+ console.log(` Run ${runNumber}/${totalRuns}: "${query}"`);
145
+ console.log(`[${'='.repeat(60)}]`);
146
+ } else {
147
+ console.log(`\n🔄 Run ${runNumber}/${totalRuns}: "${query}"`);
148
+ }
149
+
150
+ // Benchmark OLD system
151
+ if (verbose) console.log('\n[OLD SYSTEM] Running...');
152
+ const oldResult = await benchmarkOldSystem(query);
153
+ if (verbose) {
154
+ console.log(` Duration: ${oldResult.duration_ms}ms`);
155
+ console.log(` Results: ${oldResult.result_count}`);
156
+ console.log(` Memory: ${oldResult.memory_used_mb}MB`);
157
+ console.log(` Source: ${oldResult.source}`);
158
+ }
159
+
160
+ // Wait 500ms between tests
161
+ await new Promise(resolve => setTimeout(resolve, 500));
162
+
163
+ // Benchmark NEW system (cache miss first)
164
+ if (verbose) console.log('\n[NEW SYSTEM] Running (cache MISS)...');
165
+ const newResultNoCache = await benchmarkNewSystem(query, 5, false);
166
+ if (verbose) {
167
+ console.log(` Duration: ${newResultNoCache.duration_ms}ms`);
168
+ console.log(` Results: ${newResultNoCache.result_count}`);
169
+ console.log(` Memory: ${newResultNoCache.memory_used_mb}MB`);
170
+ console.log(` Engineers: ${newResultNoCache.engineers_queried}`);
171
+ console.log(` Source: ${newResultNoCache.source}`);
172
+ }
173
+
174
+ // Wait 500ms
175
+ await new Promise(resolve => setTimeout(resolve, 500));
176
+
177
+ // Benchmark NEW system (cache HIT)
178
+ if (verbose) console.log('\n[NEW SYSTEM] Running (cache HIT)...');
179
+ const newResultWithCache = await benchmarkNewSystem(query, 5, true);
180
+ if (verbose) {
181
+ console.log(` Duration: ${newResultWithCache.duration_ms}ms`);
182
+ console.log(` Results: ${newResultWithCache.result_count}`);
183
+ console.log(` Memory: ${newResultWithCache.memory_used_mb}MB`);
184
+ console.log(` Cache Hit: ${newResultWithCache.cache_hit ? 'YES ✅' : 'NO ❌'}`);
185
+ console.log(` Source: ${newResultWithCache.source}`);
186
+ }
187
+
188
+ return {
189
+ query,
190
+ old: oldResult,
191
+ new_no_cache: newResultNoCache,
192
+ new_with_cache: newResultWithCache
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Calculate aggregate statistics
198
+ */
199
+ function calculateStats(results) {
200
+ const oldTimes = results.map(r => r.old.duration_ms);
201
+ const newNoCache = results.map(r => r.new_no_cache.duration_ms);
202
+ const newWithCache = results.map(r => r.new_with_cache.duration_ms);
203
+
204
+ const avg = arr => arr.reduce((a, b) => a + b, 0) / arr.length;
205
+ const min = arr => Math.min(...arr);
206
+ const max = arr => Math.max(...arr);
207
+ const median = arr => {
208
+ const sorted = [...arr].sort((a, b) => a - b);
209
+ const mid = Math.floor(sorted.length / 2);
210
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
211
+ };
212
+
213
+ return {
214
+ old_system: {
215
+ avg_ms: Math.round(avg(oldTimes)),
216
+ min_ms: min(oldTimes),
217
+ max_ms: max(oldTimes),
218
+ median_ms: Math.round(median(oldTimes)),
219
+ avg_s: (avg(oldTimes) / 1000).toFixed(2)
220
+ },
221
+ new_system_no_cache: {
222
+ avg_ms: Math.round(avg(newNoCache)),
223
+ min_ms: min(newNoCache),
224
+ max_ms: max(newNoCache),
225
+ median_ms: Math.round(median(newNoCache)),
226
+ avg_s: (avg(newNoCache) / 1000).toFixed(2),
227
+ improvement_vs_old_pct: Math.round(((avg(oldTimes) - avg(newNoCache)) / avg(oldTimes)) * 100)
228
+ },
229
+ new_system_with_cache: {
230
+ avg_ms: Math.round(avg(newWithCache)),
231
+ min_ms: min(newWithCache),
232
+ max_ms: max(newWithCache),
233
+ median_ms: Math.round(median(newWithCache)),
234
+ avg_s: (avg(newWithCache) / 1000).toFixed(2),
235
+ improvement_vs_old_pct: Math.round(((avg(oldTimes) - avg(newWithCache)) / avg(oldTimes)) * 100),
236
+ improvement_vs_no_cache_pct: Math.round(((avg(newNoCache) - avg(newWithCache)) / avg(newNoCache)) * 100)
237
+ },
238
+ cache_hit_speedup: (avg(newNoCache) / avg(newWithCache)).toFixed(2) + 'x'
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Estimate token savings
244
+ */
245
+ function estimateTokenSavings(stats, assumedStartupCalls = 3) {
246
+ // Old system: every call hits GitHub API (~120s per call)
247
+ const oldStartupTime = stats.old_system.avg_ms * assumedStartupCalls;
248
+
249
+ // New system: first call misses cache, subsequent calls hit cache
250
+ const newStartupTime = stats.new_system_no_cache.avg_ms +
251
+ (stats.new_system_with_cache.avg_ms * (assumedStartupCalls - 1));
252
+
253
+ const timeSaved = oldStartupTime - newStartupTime;
254
+ const pctFaster = Math.round((timeSaved / oldStartupTime) * 100);
255
+
256
+ // Estimate token savings (rough heuristic: 1 second = ~50 tokens at startup)
257
+ const tokensSavedEstimate = Math.round((timeSaved / 1000) * 50);
258
+
259
+ return {
260
+ old_startup_time_ms: Math.round(oldStartupTime),
261
+ new_startup_time_ms: Math.round(newStartupTime),
262
+ time_saved_ms: Math.round(timeSaved),
263
+ percent_faster: pctFaster,
264
+ estimated_tokens_saved: tokensSavedEstimate,
265
+ assumed_startup_calls: assumedStartupCalls
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Main execution
271
+ */
272
+ async function main() {
273
+ console.log('\n╔════════════════════════════════════════════════════════════════╗');
274
+ console.log('║ BOSS CLAUDE - MEMORY SYSTEM BENCHMARK ║');
275
+ console.log('╚════════════════════════════════════════════════════════════════╝');
276
+ console.log('\nComparing:');
277
+ console.log(' OLD: Direct GitHub API calls (lib/memory.js)');
278
+ console.log(' NEW: MemorySupervisor with 4 parallel engineers + Redis cache');
279
+ console.log(`\nTest Configuration:`);
280
+ console.log(` Queries: ${TEST_QUERIES.length}`);
281
+ console.log(` Runs per query: ${numberOfRuns}`);
282
+ console.log(` Total tests: ${TEST_QUERIES.length * numberOfRuns * 3} (${TEST_QUERIES.length * numberOfRuns} per system)`);
283
+ console.log(` Verbose: ${verbose ? 'ON' : 'OFF'}`);
284
+
285
+ // Clear cache before starting
286
+ console.log('\n🔄 Clearing Redis cache...');
287
+ await invalidateMemoryCache();
288
+
289
+ const allResults = [];
290
+ let testNumber = 0;
291
+ const totalTests = TEST_QUERIES.length * numberOfRuns;
292
+
293
+ for (let run = 1; run <= numberOfRuns; run++) {
294
+ for (const query of TEST_QUERIES) {
295
+ testNumber++;
296
+ const result = await runBenchmark(query, testNumber, totalTests);
297
+ allResults.push(result);
298
+ }
299
+ }
300
+
301
+ // Calculate statistics
302
+ const stats = calculateStats(allResults);
303
+ const tokenSavings = estimateTokenSavings(stats);
304
+
305
+ // Get cache statistics
306
+ const cacheStats = await getMemoryCacheStats();
307
+
308
+ // Calculate cache hit rate
309
+ const totalNewSystemCalls = allResults.length * 2; // no-cache + with-cache
310
+ const cacheHits = allResults.filter(r => r.new_with_cache.cache_hit).length;
311
+ const cacheHitRate = Math.round((cacheHits / totalNewSystemCalls) * 100);
312
+
313
+ // Print results
314
+ console.log('\n\n╔════════════════════════════════════════════════════════════════╗');
315
+ console.log('║ BENCHMARK RESULTS ║');
316
+ console.log('╚════════════════════════════════════════════════════════════════╝');
317
+
318
+ console.log('\n📊 RESPONSE TIME COMPARISON');
319
+ console.log('─'.repeat(64));
320
+ console.log(`\nOLD SYSTEM (Direct GitHub API):`);
321
+ console.log(` Average: ${stats.old_system.avg_ms}ms (${stats.old_system.avg_s}s)`);
322
+ console.log(` Median: ${stats.old_system.median_ms}ms`);
323
+ console.log(` Range: ${stats.old_system.min_ms}ms - ${stats.old_system.max_ms}ms`);
324
+
325
+ console.log(`\nNEW SYSTEM (MemorySupervisor - Cache MISS):`);
326
+ console.log(` Average: ${stats.new_system_no_cache.avg_ms}ms (${stats.new_system_no_cache.avg_s}s)`);
327
+ console.log(` Median: ${stats.new_system_no_cache.median_ms}ms`);
328
+ console.log(` Range: ${stats.new_system_no_cache.min_ms}ms - ${stats.new_system_no_cache.max_ms}ms`);
329
+ console.log(` Improvement: ${stats.new_system_no_cache.improvement_vs_old_pct}% faster than old`);
330
+
331
+ console.log(`\nNEW SYSTEM (MemorySupervisor - Cache HIT):`);
332
+ console.log(` Average: ${stats.new_system_with_cache.avg_ms}ms (${stats.new_system_with_cache.avg_s}s)`);
333
+ console.log(` Median: ${stats.new_system_with_cache.median_ms}ms`);
334
+ console.log(` Range: ${stats.new_system_with_cache.min_ms}ms - ${stats.new_system_with_cache.max_ms}ms`);
335
+ console.log(` Improvement: ${stats.new_system_with_cache.improvement_vs_old_pct}% faster than old`);
336
+ console.log(` Improvement: ${stats.new_system_with_cache.improvement_vs_no_cache_pct}% faster than cache miss`);
337
+ console.log(` Cache Speedup: ${stats.cache_hit_speedup}`);
338
+
339
+ console.log('\n\n💾 CACHE PERFORMANCE');
340
+ console.log('─'.repeat(64));
341
+ console.log(` Cache Hit Rate: ${cacheHitRate}%`);
342
+ console.log(` Cache Hits: ${cacheHits}/${totalNewSystemCalls} calls`);
343
+ console.log(` Cached Queries: ${cacheStats.total_cached_queries}`);
344
+ console.log(` Cache Strategy: Redis with 5-minute TTL`);
345
+
346
+ console.log('\n\n🚀 STARTUP TIME IMPACT');
347
+ console.log('─'.repeat(64));
348
+ console.log(` Assumed startup calls: ${tokenSavings.assumed_startup_calls}`);
349
+ console.log(` OLD system startup: ${tokenSavings.old_startup_time_ms}ms`);
350
+ console.log(` NEW system startup: ${tokenSavings.new_startup_time_ms}ms`);
351
+ console.log(` Time saved: ${tokenSavings.time_saved_ms}ms (${tokenSavings.percent_faster}% faster)`);
352
+ console.log(` Estimated token savings: ~${tokenSavings.estimated_tokens_saved} tokens`);
353
+
354
+ console.log('\n\n🔧 ARCHITECTURE IMPROVEMENTS');
355
+ console.log('─'.repeat(64));
356
+ console.log(` OLD: Sequential GitHub API calls`);
357
+ console.log(` NEW: 4 parallel engineer agents + Redis cache`);
358
+ console.log(` Engineers: postgres-n8n-specialist, redis-architect,`);
359
+ console.log(` n8n-workflow-architect, github-expert`);
360
+ console.log(` Timeout: 5 seconds per engineer (parallel execution)`);
361
+ console.log(` Cache Layer: Redis with automatic invalidation`);
362
+
363
+ console.log('\n\n📈 TARGET METRICS');
364
+ console.log('─'.repeat(64));
365
+ console.log(` Target: <5s response (cache miss)`);
366
+ console.log(` Actual: ${stats.new_system_no_cache.avg_s}s`);
367
+ console.log(` Status: ${stats.new_system_no_cache.avg_ms < 5000 ? '✅ PASS' : '❌ FAIL'}`);
368
+ console.log(`\n Target: <1s response (cache hit)`);
369
+ console.log(` Actual: ${stats.new_system_with_cache.avg_s}s`);
370
+ console.log(` Status: ${stats.new_system_with_cache.avg_ms < 1000 ? '✅ PASS' : '⚠️ NEEDS OPTIMIZATION'}`);
371
+
372
+ // JSON output for programmatic consumption
373
+ const jsonOutput = {
374
+ benchmark: 'memory-system-comparison',
375
+ timestamp: new Date().toISOString(),
376
+ config: {
377
+ queries: TEST_QUERIES.length,
378
+ runs_per_query: numberOfRuns,
379
+ total_tests: totalTests
380
+ },
381
+ results: {
382
+ old_system: stats.old_system,
383
+ new_system_no_cache: stats.new_system_no_cache,
384
+ new_system_with_cache: stats.new_system_with_cache,
385
+ cache_performance: {
386
+ hit_rate_pct: cacheHitRate,
387
+ total_queries_cached: cacheStats.total_cached_queries,
388
+ cache_speedup: stats.cache_hit_speedup
389
+ },
390
+ startup_impact: tokenSavings,
391
+ target_metrics: {
392
+ cache_miss_target_ms: 5000,
393
+ cache_miss_actual_ms: stats.new_system_no_cache.avg_ms,
394
+ cache_miss_pass: stats.new_system_no_cache.avg_ms < 5000,
395
+ cache_hit_target_ms: 1000,
396
+ cache_hit_actual_ms: stats.new_system_with_cache.avg_ms,
397
+ cache_hit_pass: stats.new_system_with_cache.avg_ms < 1000
398
+ }
399
+ },
400
+ raw_results: verbose ? allResults : null
401
+ };
402
+
403
+ console.log('\n\n📄 JSON OUTPUT');
404
+ console.log('─'.repeat(64));
405
+ console.log(JSON.stringify(jsonOutput, null, 2));
406
+
407
+ console.log('\n\n✅ Benchmark complete!\n');
408
+
409
+ // Close connections gracefully
410
+ console.log('\n🔌 Closing connections...');
411
+ await closeConnections();
412
+
413
+ // Give a moment for cleanup to finish
414
+ await new Promise(resolve => setTimeout(resolve, 200));
415
+
416
+ console.log('✅ All connections closed\n');
417
+ process.exit(0);
418
+ }
419
+
420
+ // Run benchmark
421
+ main().catch(async (err) => {
422
+ console.error('\n❌ Benchmark failed:', err);
423
+ console.error(err.stack);
424
+
425
+ // Attempt cleanup even on error
426
+ try {
427
+ await closeConnections();
428
+ } catch (cleanupErr) {
429
+ console.warn('Cleanup error:', cleanupErr.message);
430
+ }
431
+
432
+ process.exit(1);
433
+ });
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+ # Pre-commit hook: Block commits with real credentials
3
+
4
+ PATTERNS="trolley|caboose|turntable|yamanote|5Prl6LQo|guAPbZww|sk-proj-J7Szng|proxy\.rlwy\.net"
5
+
6
+ if grep -rn -E "$PATTERNS" lib/ config/ bin/ README.md --include="*.js" --include="*.md" --include="*.json" 2>/dev/null | grep -v "check-secrets.sh"; then
7
+ echo "❌ BLOCKED: Real credentials found! Remove before committing."
8
+ exit 1
9
+ fi
10
+
11
+ echo "✅ No credentials detected"
12
+ exit 0
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createClient } from 'redis';
4
+
5
+ // Try local Redis first
6
+ const REDIS_URL = 'redis://localhost:6379';
7
+
8
+ async function fetchTodos() {
9
+ const client = createClient({ url: REDIS_URL });
10
+
11
+ try {
12
+ await client.connect();
13
+ console.log('✅ Connected to Redis (localhost:6379)');
14
+
15
+ // Check for Boss Claude todo keys
16
+ const patterns = [
17
+ 'boss:todos:*',
18
+ 'boss:tasks:*',
19
+ 'session:current:*',
20
+ 'boss:*'
21
+ ];
22
+
23
+ const allKeys = new Set();
24
+
25
+ for (const pattern of patterns) {
26
+ console.log(`\n🔍 Scanning for: ${pattern}`);
27
+ const keys = await client.keys(pattern);
28
+ keys.forEach(k => allKeys.add(k));
29
+ }
30
+
31
+ if (allKeys.size === 0) {
32
+ console.log('\n⚠️ No Boss Claude keys found in Redis');
33
+ console.log('\nSearching for ANY keys to verify connection...');
34
+
35
+ const allRedisKeys = await client.keys('*');
36
+ console.log(`Total keys in Redis: ${allRedisKeys.length}`);
37
+ allRedisKeys.slice(0, 20).forEach(k => console.log(` - ${k}`));
38
+ if (allRedisKeys.length > 20) {
39
+ console.log(' ... (showing first 20 keys)');
40
+ }
41
+
42
+ await client.disconnect();
43
+ return;
44
+ }
45
+
46
+ console.log(`\n📋 Found ${allKeys.size} Boss Claude keys:\n`);
47
+
48
+ const todoData = {};
49
+
50
+ for (const key of Array.from(allKeys).sort()) {
51
+ const type = await client.type(key);
52
+ let value;
53
+
54
+ switch (type) {
55
+ case 'string':
56
+ value = await client.get(key);
57
+ break;
58
+ case 'list':
59
+ value = await client.lRange(key, 0, -1);
60
+ break;
61
+ case 'set':
62
+ value = await client.sMembers(key);
63
+ break;
64
+ case 'zset':
65
+ value = await client.zRangeWithScores(key, 0, -1);
66
+ break;
67
+ case 'hash':
68
+ value = await client.hGetAll(key);
69
+ break;
70
+ default:
71
+ value = `<${type}>`;
72
+ }
73
+
74
+ todoData[key] = { type, value };
75
+
76
+ console.log(`\n🔑 ${key}`);
77
+ console.log(` Type: ${type}`);
78
+
79
+ if (type === 'string') {
80
+ // Try to parse as JSON
81
+ try {
82
+ const parsed = JSON.parse(value);
83
+ console.log(' Value:', JSON.stringify(parsed, null, 2).split('\n').map((l, i) => i === 0 ? l : ' ' + l).join('\n'));
84
+ } catch {
85
+ console.log(' Value:', value);
86
+ }
87
+ } else {
88
+ console.log(' Value:', JSON.stringify(value, null, 2).split('\n').map((l, i) => i === 0 ? l : ' ' + l).join('\n'));
89
+ }
90
+
91
+ // Get TTL
92
+ const ttl = await client.ttl(key);
93
+ if (ttl > 0) {
94
+ console.log(` TTL: ${ttl}s (${Math.floor(ttl / 60)} minutes)`);
95
+ } else if (ttl === -1) {
96
+ console.log(' TTL: No expiration');
97
+ }
98
+ }
99
+
100
+ // Summary
101
+ console.log('\n' + '='.repeat(80));
102
+ console.log('📊 BOSS CLAUDE TODO SUMMARY');
103
+ console.log('='.repeat(80));
104
+
105
+ // Look for main todo list
106
+ if (todoData['boss:todos:main']) {
107
+ console.log('\n✅ Main Todo List Found:');
108
+ const todos = todoData['boss:todos:main'].value;
109
+ if (typeof todos === 'string') {
110
+ try {
111
+ const parsed = JSON.parse(todos);
112
+ console.log(JSON.stringify(parsed, null, 2));
113
+ } catch {
114
+ console.log(todos);
115
+ }
116
+ } else {
117
+ console.log(JSON.stringify(todos, null, 2));
118
+ }
119
+ } else {
120
+ console.log('\n⚠️ boss:todos:main not found');
121
+ }
122
+
123
+ // Look for pending tasks
124
+ if (todoData['boss:todos:pending']) {
125
+ console.log('\n📌 Pending Tasks:');
126
+ console.log(JSON.stringify(todoData['boss:todos:pending'].value, null, 2));
127
+ }
128
+
129
+ // Look for session data
130
+ const sessionKeys = Array.from(allKeys).filter(k => k.startsWith('session:'));
131
+ if (sessionKeys.length > 0) {
132
+ console.log('\n🔄 Session Data:');
133
+ sessionKeys.forEach(key => {
134
+ console.log(` ${key}:`, JSON.stringify(todoData[key].value, null, 2));
135
+ });
136
+ }
137
+
138
+ await client.disconnect();
139
+ console.log('\n✅ Disconnected from Redis');
140
+
141
+ } catch (error) {
142
+ console.error('❌ Error:', error.message);
143
+ console.error(error.stack);
144
+ process.exit(1);
145
+ }
146
+ }
147
+
148
+ fetchTodos();