@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.
- package/README.md +304 -1
- package/bin/boss-claude.js +1138 -0
- package/bin/commands/mode.js +250 -0
- package/bin/onyx-guard.js +259 -0
- package/bin/onyx-guard.sh +251 -0
- package/bin/prompts.js +284 -0
- package/bin/rollback.js +85 -0
- package/bin/setup-wizard.js +492 -0
- package/config/.env.example +17 -0
- package/lib/README.md +83 -0
- package/lib/agent-logger.js +61 -0
- package/lib/agents/memory-engineers/github-memory-engineer.js +251 -0
- package/lib/agents/memory-engineers/postgres-memory-engineer.js +633 -0
- package/lib/agents/memory-engineers/qdrant-memory-engineer.js +358 -0
- package/lib/agents/memory-engineers/redis-memory-engineer.js +383 -0
- package/lib/agents/memory-supervisor.js +526 -0
- package/lib/agents/registry.js +135 -0
- package/lib/auto-monitor.js +131 -0
- package/lib/checkpoint-hook.js +112 -0
- package/lib/checkpoint.js +319 -0
- package/lib/commentator.js +213 -0
- package/lib/context-scribe.js +120 -0
- package/lib/delegation-strategies.js +326 -0
- package/lib/hierarchy-validator.js +643 -0
- package/lib/index.js +15 -0
- package/lib/init-with-mode.js +261 -0
- package/lib/init.js +44 -6
- package/lib/memory-result-aggregator.js +252 -0
- package/lib/memory.js +35 -7
- package/lib/mode-enforcer.js +473 -0
- package/lib/onyx-banner.js +169 -0
- package/lib/onyx-identity.js +214 -0
- package/lib/onyx-monitor.js +381 -0
- package/lib/onyx-reminder.js +188 -0
- package/lib/onyx-tool-interceptor.js +341 -0
- package/lib/onyx-wrapper.js +315 -0
- package/lib/orchestrator-gate.js +334 -0
- package/lib/output-formatter.js +296 -0
- package/lib/postgres.js +1 -1
- package/lib/prompt-injector.js +220 -0
- package/lib/prompts.js +532 -0
- package/lib/session.js +153 -6
- package/lib/setup/README.md +187 -0
- package/lib/setup/env-manager.js +785 -0
- package/lib/setup/error-recovery.js +630 -0
- package/lib/setup/explain-scopes.js +385 -0
- package/lib/setup/github-instructions.js +333 -0
- package/lib/setup/github-repo.js +254 -0
- package/lib/setup/import-credentials.js +498 -0
- package/lib/setup/index.js +62 -0
- package/lib/setup/init-postgres.js +785 -0
- package/lib/setup/init-redis.js +456 -0
- package/lib/setup/integration-test.js +652 -0
- package/lib/setup/progress.js +357 -0
- package/lib/setup/rollback.js +670 -0
- package/lib/setup/rollback.test.js +452 -0
- package/lib/setup/setup-with-rollback.example.js +351 -0
- package/lib/setup/summary.js +400 -0
- package/lib/setup/test-github-setup.js +10 -0
- package/lib/setup/test-postgres-init.js +98 -0
- package/lib/setup/verify-setup.js +102 -0
- package/lib/task-agent-worker.js +235 -0
- package/lib/token-monitor.js +466 -0
- package/lib/tool-wrapper-integration.js +369 -0
- package/lib/tool-wrapper.js +387 -0
- package/lib/validators/README.md +497 -0
- package/lib/validators/config.js +583 -0
- package/lib/validators/config.test.js +175 -0
- package/lib/validators/github.js +310 -0
- package/lib/validators/github.test.js +61 -0
- package/lib/validators/index.js +15 -0
- package/lib/validators/postgres.js +525 -0
- package/package.json +98 -13
- package/scripts/benchmark-memory.js +433 -0
- package/scripts/check-secrets.sh +12 -0
- package/scripts/fetch-todos.mjs +148 -0
- package/scripts/graceful-shutdown.sh +156 -0
- package/scripts/install-onyx-hooks.js +373 -0
- package/scripts/install.js +119 -18
- package/scripts/redis-monitor.js +284 -0
- package/scripts/redis-setup.js +412 -0
- package/scripts/test-memory-retrieval.js +201 -0
- package/scripts/validate-exports.js +68 -0
- package/scripts/validate-package.js +120 -0
- package/scripts/verify-onyx-deployment.js +309 -0
- package/scripts/verify-redis-deployment.js +354 -0
- package/scripts/verify-redis-init.js +219 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* REDIS IDENTITY LOCK SYSTEM - DEPLOYMENT VERIFICATION
|
|
5
|
+
*
|
|
6
|
+
* This script verifies that the Redis-based mode enforcement system
|
|
7
|
+
* is properly deployed and functional.
|
|
8
|
+
*
|
|
9
|
+
* Run: node scripts/verify-redis-deployment.js
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { getEnforcer, MODES } from '../lib/mode-enforcer.js';
|
|
13
|
+
import { getGate } from '../lib/orchestrator-gate.js';
|
|
14
|
+
import { loadIdentity } from '../lib/identity.js';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
|
|
17
|
+
const CHECKS = {
|
|
18
|
+
passed: 0,
|
|
19
|
+
failed: 0,
|
|
20
|
+
warnings: 0
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function logCheck(status, message) {
|
|
24
|
+
const icons = {
|
|
25
|
+
pass: chalk.green('✓'),
|
|
26
|
+
fail: chalk.red('✗'),
|
|
27
|
+
warn: chalk.yellow('⚠')
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
console.log(`${icons[status]} ${message}`);
|
|
31
|
+
|
|
32
|
+
if (status === 'pass') CHECKS.passed++;
|
|
33
|
+
if (status === 'fail') CHECKS.failed++;
|
|
34
|
+
if (status === 'warn') CHECKS.warnings++;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function logSection(title) {
|
|
38
|
+
console.log(`\n${chalk.cyan.bold('═'.repeat(60))}`);
|
|
39
|
+
console.log(chalk.cyan.bold(` ${title}`));
|
|
40
|
+
console.log(`${chalk.cyan.bold('═'.repeat(60))}\n`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function verify() {
|
|
44
|
+
console.log(chalk.bold.white('\n╔══════════════════════════════════════════════════════════╗'));
|
|
45
|
+
console.log(chalk.bold.white('║ REDIS IDENTITY LOCK SYSTEM - DEPLOYMENT VERIFICATION ║'));
|
|
46
|
+
console.log(chalk.bold.white('╚══════════════════════════════════════════════════════════╝\n'));
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// ==========================================
|
|
50
|
+
// CHECK 1: Redis Connection
|
|
51
|
+
// ==========================================
|
|
52
|
+
logSection('1. Redis Connection');
|
|
53
|
+
|
|
54
|
+
const enforcer = getEnforcer();
|
|
55
|
+
const gate = getGate();
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await enforcer.getCurrentMode();
|
|
59
|
+
logCheck('pass', 'Redis connection successful');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logCheck('fail', `Redis connection failed: ${error.message}`);
|
|
62
|
+
console.log(chalk.red('\nREDIS_URL must be set. Check ~/.boss-claude/.env or project .env'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ==========================================
|
|
67
|
+
// CHECK 2: Mode Enforcement System
|
|
68
|
+
// ==========================================
|
|
69
|
+
logSection('2. Mode Enforcement System');
|
|
70
|
+
|
|
71
|
+
// Test setting mode
|
|
72
|
+
try {
|
|
73
|
+
await enforcer.setMode(MODES.WORKER, {
|
|
74
|
+
agent: 'deployment-test',
|
|
75
|
+
reason: 'verification-script'
|
|
76
|
+
});
|
|
77
|
+
logCheck('pass', 'Mode setting works');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logCheck('fail', `Mode setting failed: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Test getting mode
|
|
83
|
+
try {
|
|
84
|
+
const mode = await enforcer.getCurrentMode();
|
|
85
|
+
if (mode === MODES.WORKER) {
|
|
86
|
+
logCheck('pass', `Current mode retrieved: ${mode}`);
|
|
87
|
+
} else {
|
|
88
|
+
logCheck('warn', `Unexpected mode: ${mode}`);
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logCheck('fail', `Mode retrieval failed: ${error.message}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Test mode metadata
|
|
95
|
+
try {
|
|
96
|
+
const metadata = await enforcer.getModeMetadata();
|
|
97
|
+
if (metadata && metadata.setBy === 'deployment-test') {
|
|
98
|
+
logCheck('pass', 'Mode metadata stored correctly');
|
|
99
|
+
} else {
|
|
100
|
+
logCheck('warn', 'Mode metadata incomplete');
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
logCheck('fail', `Metadata retrieval failed: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ==========================================
|
|
107
|
+
// CHECK 3: Capability Enforcement
|
|
108
|
+
// ==========================================
|
|
109
|
+
logSection('3. Capability Enforcement');
|
|
110
|
+
|
|
111
|
+
// Test that WORKER mode blocks delegation
|
|
112
|
+
try {
|
|
113
|
+
await enforcer.setMode(MODES.WORKER, {
|
|
114
|
+
agent: 'test-worker',
|
|
115
|
+
reason: 'capability-test'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
await enforcer.checkCapability('canDelegate', 'Test delegation');
|
|
120
|
+
logCheck('fail', 'Worker mode should block delegation');
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error.message.includes('CAPABILITY ENFORCEMENT')) {
|
|
123
|
+
logCheck('pass', 'Worker mode correctly blocks delegation');
|
|
124
|
+
} else {
|
|
125
|
+
logCheck('warn', `Unexpected error: ${error.message}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
logCheck('fail', `Capability test failed: ${error.message}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Test that ORCHESTRATOR mode allows delegation
|
|
133
|
+
try {
|
|
134
|
+
await enforcer.setMode(MODES.ORCHESTRATOR, {
|
|
135
|
+
agent: 'test-orchestrator',
|
|
136
|
+
reason: 'capability-test'
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await enforcer.checkCapability('canDelegate', 'Test delegation');
|
|
140
|
+
logCheck('pass', 'Orchestrator mode allows delegation');
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logCheck('fail', `Orchestrator capability test failed: ${error.message}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ==========================================
|
|
146
|
+
// CHECK 4: Token Budget Enforcement
|
|
147
|
+
// ==========================================
|
|
148
|
+
logSection('4. Token Budget Enforcement');
|
|
149
|
+
|
|
150
|
+
// Test token budget for WORKER mode (max 20k)
|
|
151
|
+
try {
|
|
152
|
+
await enforcer.setMode(MODES.WORKER, {
|
|
153
|
+
agent: 'test-worker',
|
|
154
|
+
reason: 'token-budget-test'
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
await enforcer.enforceTokenBudget(50000, 'Large task');
|
|
159
|
+
logCheck('fail', 'Worker mode should block 50k token budget');
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (error.message.includes('TOKEN BUDGET ENFORCEMENT')) {
|
|
162
|
+
logCheck('pass', 'Token budget enforcement works (blocks 50k for worker)');
|
|
163
|
+
} else {
|
|
164
|
+
logCheck('warn', `Unexpected error: ${error.message}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
logCheck('fail', `Token budget test failed: ${error.message}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Test token budget within limits
|
|
172
|
+
try {
|
|
173
|
+
await enforcer.enforceTokenBudget(10000, 'Small task');
|
|
174
|
+
logCheck('pass', 'Token budget allows tasks within limits');
|
|
175
|
+
} catch (error) {
|
|
176
|
+
logCheck('fail', `Token budget within-limits test failed: ${error.message}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ==========================================
|
|
180
|
+
// CHECK 5: Orchestrator Gate Integration
|
|
181
|
+
// ==========================================
|
|
182
|
+
logSection('5. Orchestrator Gate Integration');
|
|
183
|
+
|
|
184
|
+
// Test gate status retrieval
|
|
185
|
+
try {
|
|
186
|
+
const status = await gate.getStatus();
|
|
187
|
+
if (status.mode && status.capabilities && status.restrictions) {
|
|
188
|
+
logCheck('pass', 'Gate status retrieval works');
|
|
189
|
+
} else {
|
|
190
|
+
logCheck('warn', 'Gate status incomplete');
|
|
191
|
+
}
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logCheck('fail', `Gate status failed: ${error.message}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Test gate beforeExecute
|
|
197
|
+
try {
|
|
198
|
+
await enforcer.setMode(MODES.WORKER, {
|
|
199
|
+
agent: 'test-worker',
|
|
200
|
+
reason: 'gate-test'
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
await gate.beforeExecute(
|
|
204
|
+
{ description: 'Test execution' },
|
|
205
|
+
5000
|
|
206
|
+
);
|
|
207
|
+
logCheck('pass', 'Gate beforeExecute works');
|
|
208
|
+
} catch (error) {
|
|
209
|
+
logCheck('fail', `Gate beforeExecute failed: ${error.message}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Test gate blocks delegation in worker mode
|
|
213
|
+
try {
|
|
214
|
+
try {
|
|
215
|
+
await gate.beforeDelegate(
|
|
216
|
+
'postgres-specialist',
|
|
217
|
+
{ description: 'Test delegation' },
|
|
218
|
+
10000
|
|
219
|
+
);
|
|
220
|
+
logCheck('fail', 'Gate should block delegation in worker mode');
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error.message.includes('GATE BLOCKED')) {
|
|
223
|
+
logCheck('pass', 'Gate correctly blocks delegation in worker mode');
|
|
224
|
+
} else {
|
|
225
|
+
logCheck('warn', `Unexpected error: ${error.message}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
} catch (error) {
|
|
229
|
+
logCheck('fail', `Gate delegation test failed: ${error.message}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ==========================================
|
|
233
|
+
// CHECK 6: Mode History & Audit Trail
|
|
234
|
+
// ==========================================
|
|
235
|
+
logSection('6. Mode History & Audit Trail');
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
const history = await enforcer.getModeHistory(5);
|
|
239
|
+
if (history && history.length > 0) {
|
|
240
|
+
logCheck('pass', `Mode history tracked (${history.length} entries)`);
|
|
241
|
+
} else {
|
|
242
|
+
logCheck('warn', 'Mode history empty');
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
logCheck('fail', `Mode history retrieval failed: ${error.message}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const blocked = await enforcer.getBlockedActions(5);
|
|
250
|
+
if (blocked !== undefined) {
|
|
251
|
+
logCheck('pass', `Blocked actions log available (${blocked.length} entries)`);
|
|
252
|
+
} else {
|
|
253
|
+
logCheck('warn', 'Blocked actions log unavailable');
|
|
254
|
+
}
|
|
255
|
+
} catch (error) {
|
|
256
|
+
logCheck('fail', `Blocked actions retrieval failed: ${error.message}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const stats = await enforcer.getModeStats();
|
|
261
|
+
if (stats && Object.keys(stats).length > 0) {
|
|
262
|
+
logCheck('pass', 'Mode statistics tracked');
|
|
263
|
+
} else {
|
|
264
|
+
logCheck('warn', 'Mode statistics empty');
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
logCheck('fail', `Mode stats retrieval failed: ${error.message}`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ==========================================
|
|
271
|
+
// CHECK 7: Agent Identity Tracking
|
|
272
|
+
// ==========================================
|
|
273
|
+
logSection('7. Agent Identity Tracking');
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
await enforcer.setAgentIdentity('test-agent', 'testing');
|
|
277
|
+
const identity = await enforcer.getAgentIdentity();
|
|
278
|
+
|
|
279
|
+
if (identity && identity.agent === 'test-agent' && identity.domain === 'testing') {
|
|
280
|
+
logCheck('pass', 'Agent identity tracking works');
|
|
281
|
+
} else {
|
|
282
|
+
logCheck('warn', 'Agent identity incomplete');
|
|
283
|
+
}
|
|
284
|
+
} catch (error) {
|
|
285
|
+
logCheck('fail', `Agent identity test failed: ${error.message}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ==========================================
|
|
289
|
+
// CHECK 8: Boss Identity Integration
|
|
290
|
+
// ==========================================
|
|
291
|
+
logSection('8. Boss Identity Integration');
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
const bossIdentity = await loadIdentity();
|
|
295
|
+
if (bossIdentity && bossIdentity.level !== undefined) {
|
|
296
|
+
logCheck('pass', `Boss identity loaded (Level ${bossIdentity.level})`);
|
|
297
|
+
} else {
|
|
298
|
+
logCheck('warn', 'Boss identity incomplete');
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
logCheck('fail', `Boss identity load failed: ${error.message}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ==========================================
|
|
305
|
+
// CHECK 9: Emergency Reset
|
|
306
|
+
// ==========================================
|
|
307
|
+
logSection('9. Emergency Reset');
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
await enforcer.resetMode();
|
|
311
|
+
const mode = await enforcer.getCurrentMode();
|
|
312
|
+
|
|
313
|
+
if (mode === MODES.WORKER) {
|
|
314
|
+
logCheck('pass', 'Emergency reset works (defaults to WORKER)');
|
|
315
|
+
} else {
|
|
316
|
+
logCheck('warn', `Emergency reset returned unexpected mode: ${mode}`);
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
logCheck('fail', `Emergency reset failed: ${error.message}`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ==========================================
|
|
323
|
+
// FINAL REPORT
|
|
324
|
+
// ==========================================
|
|
325
|
+
console.log(chalk.bold.white('\n╔══════════════════════════════════════════════════════════╗'));
|
|
326
|
+
console.log(chalk.bold.white('║ DEPLOYMENT VERIFICATION REPORT ║'));
|
|
327
|
+
console.log(chalk.bold.white('╚══════════════════════════════════════════════════════════╝\n'));
|
|
328
|
+
|
|
329
|
+
console.log(`${chalk.green('Passed:')} ${CHECKS.passed}`);
|
|
330
|
+
console.log(`${chalk.red('Failed:')} ${CHECKS.failed}`);
|
|
331
|
+
console.log(`${chalk.yellow('Warnings:')} ${CHECKS.warnings}`);
|
|
332
|
+
|
|
333
|
+
console.log('');
|
|
334
|
+
|
|
335
|
+
if (CHECKS.failed === 0 && CHECKS.warnings === 0) {
|
|
336
|
+
console.log(chalk.green.bold('✓ ALL CHECKS PASSED - System fully operational!\n'));
|
|
337
|
+
process.exit(0);
|
|
338
|
+
} else if (CHECKS.failed === 0) {
|
|
339
|
+
console.log(chalk.yellow.bold('⚠ System operational with warnings\n'));
|
|
340
|
+
process.exit(0);
|
|
341
|
+
} else {
|
|
342
|
+
console.log(chalk.red.bold('✗ System has failures - review errors above\n'));
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error(chalk.red.bold(`\n✗ Verification failed: ${error.message}\n`));
|
|
348
|
+
console.error(error.stack);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Run verification
|
|
354
|
+
verify();
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Redis Initialization Verification Script
|
|
5
|
+
*
|
|
6
|
+
* Quick script to verify Redis initialization is working correctly.
|
|
7
|
+
* Run this after setup to confirm all structures are in place.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/verify-redis-init.js
|
|
11
|
+
*
|
|
12
|
+
* Or from anywhere:
|
|
13
|
+
* boss-claude redis:verify
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import chalk from 'chalk';
|
|
17
|
+
import { verifyRedis, getRedisStats } from '../lib/setup/init-redis.js';
|
|
18
|
+
import dotenv from 'dotenv';
|
|
19
|
+
import { join } from 'path';
|
|
20
|
+
import os from 'os';
|
|
21
|
+
import { existsSync } from 'fs';
|
|
22
|
+
|
|
23
|
+
// Load environment variables
|
|
24
|
+
const envPath = join(os.homedir(), '.boss-claude', '.env');
|
|
25
|
+
if (existsSync(envPath)) {
|
|
26
|
+
dotenv.config({ path: envPath });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function main() {
|
|
30
|
+
console.log(chalk.blue('\n🔍 Boss Claude Redis Verification\n'));
|
|
31
|
+
|
|
32
|
+
// Check for Redis URL
|
|
33
|
+
if (!process.env.REDIS_URL) {
|
|
34
|
+
console.log(chalk.red('✗ REDIS_URL not configured'));
|
|
35
|
+
console.log(chalk.dim('\nPlease run: boss-claude setup\n'));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log(chalk.dim(`Redis URL: ${process.env.REDIS_URL.split('@')[1] || 'configured'}\n`));
|
|
40
|
+
|
|
41
|
+
// Step 1: Verify connection and structures
|
|
42
|
+
console.log(chalk.bold('Step 1: Verifying Connection & Structures'));
|
|
43
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const verification = await verifyRedis(process.env.REDIS_URL);
|
|
47
|
+
|
|
48
|
+
if (!verification.connected) {
|
|
49
|
+
console.log(chalk.red('✗ Connection Failed'));
|
|
50
|
+
console.log(chalk.dim(` Error: ${verification.error}\n`));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(chalk.green('✓ Connection Successful'));
|
|
55
|
+
console.log(chalk.dim(` Redis Version: ${verification.version}`));
|
|
56
|
+
|
|
57
|
+
// Check structures
|
|
58
|
+
console.log();
|
|
59
|
+
if (verification.structures.identity) {
|
|
60
|
+
console.log(chalk.green('✓ boss:identity exists'));
|
|
61
|
+
} else {
|
|
62
|
+
console.log(chalk.red('✗ boss:identity missing'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (verification.structures.sessionHistory >= 0) {
|
|
66
|
+
console.log(chalk.green(`✓ boss:sessions:history exists (${verification.structures.sessionHistory} sessions)`));
|
|
67
|
+
} else {
|
|
68
|
+
console.log(chalk.red('✗ boss:sessions:history missing'));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (verification.structures.leaderboard >= 0) {
|
|
72
|
+
console.log(chalk.green(`✓ boss:leaderboard:xp exists (${verification.structures.leaderboard} users)`));
|
|
73
|
+
} else {
|
|
74
|
+
console.log(chalk.red('✗ boss:leaderboard:xp missing'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Health check results
|
|
78
|
+
console.log();
|
|
79
|
+
if (verification.healthCheck.passed) {
|
|
80
|
+
console.log(chalk.green('✓ All health checks passed'));
|
|
81
|
+
} else {
|
|
82
|
+
console.log(chalk.red('✗ Health check failed'));
|
|
83
|
+
console.log();
|
|
84
|
+
Object.entries(verification.healthCheck.details).forEach(([key, value]) => {
|
|
85
|
+
const status = value === 'OK' ? chalk.green('✓') : chalk.red('✗');
|
|
86
|
+
console.log(` ${status} ${key}: ${chalk.dim(value)}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.log(chalk.red(`✗ Verification failed: ${error.message}\n`));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Step 2: Get statistics
|
|
96
|
+
console.log('\n' + chalk.bold('Step 2: Redis Statistics'));
|
|
97
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const stats = await getRedisStats(process.env.REDIS_URL);
|
|
101
|
+
|
|
102
|
+
if (stats.identity) {
|
|
103
|
+
console.log(chalk.cyan('\nBoss Identity:'));
|
|
104
|
+
console.log(` Level: ${chalk.yellow(stats.identity.level)}`);
|
|
105
|
+
console.log(` XP: ${chalk.cyan(stats.identity.xp)}`);
|
|
106
|
+
console.log(` Token Bank: ${chalk.magenta(stats.identity.token_bank.toLocaleString())}`);
|
|
107
|
+
console.log(` Total Sessions: ${chalk.blue(stats.identity.total_sessions)}`);
|
|
108
|
+
console.log(` Repos Managed: ${chalk.green(stats.identity.repos_managed)}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log(chalk.cyan('\nData Structures:'));
|
|
112
|
+
console.log(` Session History: ${chalk.cyan(stats.totalSessions)} sessions`);
|
|
113
|
+
console.log(` Tracked Repos: ${chalk.green(stats.totalRepos)} repositories`);
|
|
114
|
+
console.log(` Active Sessions: ${chalk.yellow(stats.activeSessions)}`);
|
|
115
|
+
console.log(` Leaderboard Size: ${chalk.blue(stats.leaderboardSize)} users`);
|
|
116
|
+
console.log(` Cache Keys: ${chalk.magenta(stats.cacheKeys)}`);
|
|
117
|
+
|
|
118
|
+
if (Object.keys(stats.achievements).length > 0) {
|
|
119
|
+
console.log(chalk.cyan('\nAchievements:'));
|
|
120
|
+
Object.entries(stats.achievements).forEach(([user, achievements]) => {
|
|
121
|
+
const achievementList = achievements.length > 0 ? achievements.join(', ') : chalk.dim('none');
|
|
122
|
+
console.log(` ${chalk.cyan(user)}: ${achievementList}`);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.log(chalk.red(`✗ Failed to get stats: ${error.message}\n`));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Step 3: Recommendations
|
|
132
|
+
console.log('\n' + chalk.bold('Step 3: Recommendations'));
|
|
133
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
134
|
+
|
|
135
|
+
const verification = await verifyRedis(process.env.REDIS_URL);
|
|
136
|
+
const stats = await getRedisStats(process.env.REDIS_URL);
|
|
137
|
+
|
|
138
|
+
const recommendations = [];
|
|
139
|
+
|
|
140
|
+
// Check if identity needs initialization
|
|
141
|
+
if (!verification.structures.identity) {
|
|
142
|
+
recommendations.push({
|
|
143
|
+
level: 'critical',
|
|
144
|
+
message: 'Boss identity not found',
|
|
145
|
+
action: 'Run: boss-claude redis:init'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check if health check failed
|
|
150
|
+
if (!verification.healthCheck.passed) {
|
|
151
|
+
recommendations.push({
|
|
152
|
+
level: 'warning',
|
|
153
|
+
message: 'Health checks failed',
|
|
154
|
+
action: 'Run: boss-claude redis:init --force'
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check for stale cache keys
|
|
159
|
+
if (stats.cacheKeys > 100) {
|
|
160
|
+
recommendations.push({
|
|
161
|
+
level: 'info',
|
|
162
|
+
message: `${stats.cacheKeys} cache keys (may need cleanup)`,
|
|
163
|
+
action: 'Cache keys auto-expire after 1 hour'
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check for active sessions without recent activity
|
|
168
|
+
if (stats.activeSessions > 5) {
|
|
169
|
+
recommendations.push({
|
|
170
|
+
level: 'info',
|
|
171
|
+
message: `${stats.activeSessions} active sessions`,
|
|
172
|
+
action: 'Consider completing or saving old sessions'
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (recommendations.length === 0) {
|
|
177
|
+
console.log(chalk.green('✓ Everything looks good!'));
|
|
178
|
+
console.log(chalk.dim('\nNo recommendations at this time.\n'));
|
|
179
|
+
} else {
|
|
180
|
+
console.log();
|
|
181
|
+
recommendations.forEach((rec) => {
|
|
182
|
+
let icon = '●';
|
|
183
|
+
let color = chalk.blue;
|
|
184
|
+
|
|
185
|
+
if (rec.level === 'critical') {
|
|
186
|
+
icon = '✗';
|
|
187
|
+
color = chalk.red;
|
|
188
|
+
} else if (rec.level === 'warning') {
|
|
189
|
+
icon = '⚠';
|
|
190
|
+
color = chalk.yellow;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log(color(`${icon} ${rec.message}`));
|
|
194
|
+
console.log(chalk.dim(` → ${rec.action}`));
|
|
195
|
+
console.log();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Success summary
|
|
200
|
+
console.log(chalk.bold('Verification Complete'));
|
|
201
|
+
console.log(chalk.dim('─'.repeat(50)));
|
|
202
|
+
|
|
203
|
+
if (verification.healthCheck.passed) {
|
|
204
|
+
console.log(chalk.green('\n✓ Redis is properly initialized and healthy'));
|
|
205
|
+
console.log(chalk.dim('\nYou can now use Boss Claude with confidence!\n'));
|
|
206
|
+
process.exit(0);
|
|
207
|
+
} else {
|
|
208
|
+
console.log(chalk.yellow('\n⚠ Redis needs attention'));
|
|
209
|
+
console.log(chalk.dim('\nFollow the recommendations above to fix issues.\n'));
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Run verification
|
|
215
|
+
main().catch((error) => {
|
|
216
|
+
console.error(chalk.red('\n✗ Verification script failed:'), error.message);
|
|
217
|
+
console.error(chalk.dim(error.stack));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
});
|