@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,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boss Claude Redis Initialization
|
|
3
|
+
*
|
|
4
|
+
* Sets up all required Redis data structures according to REDIS-ARCHITECTURE.md
|
|
5
|
+
* Creates default Boss identity and initializes core data structures.
|
|
6
|
+
*
|
|
7
|
+
* Data Structures Initialized:
|
|
8
|
+
* - boss:identity (String/JSON) - Global Boss Claude state
|
|
9
|
+
* - boss:sessions:history (Sorted Set) - Temporal session index
|
|
10
|
+
* - boss:leaderboard:xp (Sorted Set) - Global XP ranking
|
|
11
|
+
* - boss:achievements:{user} (Set) - Achievement tracking
|
|
12
|
+
*
|
|
13
|
+
* This module runs automatically during setup wizard and can be
|
|
14
|
+
* re-run safely to repair/reset the Redis state.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Redis from 'ioredis';
|
|
18
|
+
import chalk from 'chalk';
|
|
19
|
+
|
|
20
|
+
// Default identity configuration
|
|
21
|
+
const DEFAULT_IDENTITY = {
|
|
22
|
+
level: 1,
|
|
23
|
+
xp: 0,
|
|
24
|
+
token_bank: 0,
|
|
25
|
+
total_sessions: 0,
|
|
26
|
+
repos_managed: 0,
|
|
27
|
+
created_at: new Date().toISOString(),
|
|
28
|
+
updated_at: new Date().toISOString()
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Available achievements (for reference)
|
|
32
|
+
const ACHIEVEMENTS = [
|
|
33
|
+
'first_session', // Complete first session
|
|
34
|
+
'level_5', // Reach level 5
|
|
35
|
+
'level_10', // Reach level 10
|
|
36
|
+
'token_saver', // Save 100k tokens
|
|
37
|
+
'perfect_execution', // 10 sessions with no errors
|
|
38
|
+
'speed_demon', // Complete task in under 1 min
|
|
39
|
+
'repo_master', // Manage 10+ repos
|
|
40
|
+
'consistency_king', // 7 day streak
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initialize Redis with all required data structures
|
|
45
|
+
*
|
|
46
|
+
* @param {string} redisUrl - Redis connection string
|
|
47
|
+
* @param {string} username - GitHub username for user-specific data
|
|
48
|
+
* @param {boolean} force - Force re-initialization even if data exists
|
|
49
|
+
* @returns {Promise<Object>} Initialization results
|
|
50
|
+
*/
|
|
51
|
+
export async function initializeRedis(redisUrl, username = 'default', force = false) {
|
|
52
|
+
const client = new Redis(redisUrl);
|
|
53
|
+
const results = {
|
|
54
|
+
identity: { created: false, existed: false },
|
|
55
|
+
history: { created: false, existed: false },
|
|
56
|
+
leaderboard: { created: false, existed: false },
|
|
57
|
+
achievements: { created: false, existed: false },
|
|
58
|
+
healthCheck: { passed: false }
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Test connection
|
|
63
|
+
await client.ping();
|
|
64
|
+
|
|
65
|
+
// 1. Initialize Boss Identity
|
|
66
|
+
const identityExists = await client.exists('boss:identity');
|
|
67
|
+
|
|
68
|
+
if (!identityExists || force) {
|
|
69
|
+
await client.set('boss:identity', JSON.stringify(DEFAULT_IDENTITY));
|
|
70
|
+
results.identity.created = true;
|
|
71
|
+
|
|
72
|
+
if (identityExists && force) {
|
|
73
|
+
results.identity.existed = true;
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
results.identity.existed = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 2. Initialize Session History (Sorted Set)
|
|
80
|
+
// This is a sorted set, so we just verify it exists
|
|
81
|
+
const historyExists = await client.exists('boss:sessions:history');
|
|
82
|
+
|
|
83
|
+
if (!historyExists) {
|
|
84
|
+
// Initialize empty sorted set by adding and removing a dummy entry
|
|
85
|
+
await client.zadd('boss:sessions:history', 0, '__init__');
|
|
86
|
+
await client.zrem('boss:sessions:history', '__init__');
|
|
87
|
+
results.history.created = true;
|
|
88
|
+
} else {
|
|
89
|
+
results.history.existed = true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 3. Initialize Leaderboard (Sorted Set)
|
|
93
|
+
const leaderboardExists = await client.exists('boss:leaderboard:xp');
|
|
94
|
+
|
|
95
|
+
if (!leaderboardExists || force) {
|
|
96
|
+
// Add initial user with 0 XP
|
|
97
|
+
await client.zadd('boss:leaderboard:xp', 0, username);
|
|
98
|
+
results.leaderboard.created = true;
|
|
99
|
+
|
|
100
|
+
if (leaderboardExists && force) {
|
|
101
|
+
results.leaderboard.existed = true;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Update existing user or add if not present
|
|
105
|
+
const userExists = await client.zscore('boss:leaderboard:xp', username);
|
|
106
|
+
if (!userExists) {
|
|
107
|
+
await client.zadd('boss:leaderboard:xp', 0, username);
|
|
108
|
+
results.leaderboard.created = true;
|
|
109
|
+
} else {
|
|
110
|
+
results.leaderboard.existed = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 4. Initialize Achievements (Set)
|
|
115
|
+
const achievementsKey = `boss:achievements:${username}`;
|
|
116
|
+
const achievementsExist = await client.exists(achievementsKey);
|
|
117
|
+
|
|
118
|
+
if (!achievementsExist) {
|
|
119
|
+
// Initialize empty set by adding and removing a dummy entry
|
|
120
|
+
await client.sadd(achievementsKey, '__init__');
|
|
121
|
+
await client.srem(achievementsKey, '__init__');
|
|
122
|
+
results.achievements.created = true;
|
|
123
|
+
} else {
|
|
124
|
+
results.achievements.existed = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 5. Health check
|
|
128
|
+
const healthCheckResult = await performHealthCheck(client);
|
|
129
|
+
results.healthCheck = healthCheckResult;
|
|
130
|
+
|
|
131
|
+
return results;
|
|
132
|
+
|
|
133
|
+
} catch (error) {
|
|
134
|
+
throw new Error(`Redis initialization failed: ${error.message}`);
|
|
135
|
+
} finally {
|
|
136
|
+
await client.quit();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Perform comprehensive health check on Redis data structures
|
|
142
|
+
*
|
|
143
|
+
* @param {Redis} client - Connected Redis client
|
|
144
|
+
* @returns {Promise<Object>} Health check results
|
|
145
|
+
*/
|
|
146
|
+
async function performHealthCheck(client) {
|
|
147
|
+
const checks = {
|
|
148
|
+
passed: true,
|
|
149
|
+
details: {}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Check 1: Identity exists and is valid JSON
|
|
154
|
+
const identity = await client.get('boss:identity');
|
|
155
|
+
if (!identity) {
|
|
156
|
+
checks.passed = false;
|
|
157
|
+
checks.details.identity = 'Missing boss:identity key';
|
|
158
|
+
} else {
|
|
159
|
+
try {
|
|
160
|
+
const parsed = JSON.parse(identity);
|
|
161
|
+
const requiredFields = ['level', 'xp', 'token_bank', 'total_sessions', 'repos_managed'];
|
|
162
|
+
const missingFields = requiredFields.filter(field => !(field in parsed));
|
|
163
|
+
|
|
164
|
+
if (missingFields.length > 0) {
|
|
165
|
+
checks.passed = false;
|
|
166
|
+
checks.details.identity = `Missing fields: ${missingFields.join(', ')}`;
|
|
167
|
+
} else {
|
|
168
|
+
checks.details.identity = 'OK';
|
|
169
|
+
}
|
|
170
|
+
} catch (e) {
|
|
171
|
+
checks.passed = false;
|
|
172
|
+
checks.details.identity = 'Invalid JSON format';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Check 2: Session history is a sorted set
|
|
177
|
+
const historyType = await client.type('boss:sessions:history');
|
|
178
|
+
if (historyType !== 'zset' && historyType !== 'none') {
|
|
179
|
+
checks.passed = false;
|
|
180
|
+
checks.details.history = `Wrong type: ${historyType} (expected: zset)`;
|
|
181
|
+
} else {
|
|
182
|
+
checks.details.history = 'OK';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check 3: Leaderboard is a sorted set
|
|
186
|
+
const leaderboardType = await client.type('boss:leaderboard:xp');
|
|
187
|
+
if (leaderboardType !== 'zset' && leaderboardType !== 'none') {
|
|
188
|
+
checks.passed = false;
|
|
189
|
+
checks.details.leaderboard = `Wrong type: ${leaderboardType} (expected: zset)`;
|
|
190
|
+
} else {
|
|
191
|
+
checks.details.leaderboard = 'OK';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check 4: Test read/write operations
|
|
195
|
+
const testKey = 'boss:healthcheck:test';
|
|
196
|
+
const testValue = Date.now().toString();
|
|
197
|
+
|
|
198
|
+
await client.set(testKey, testValue);
|
|
199
|
+
const retrieved = await client.get(testKey);
|
|
200
|
+
await client.del(testKey);
|
|
201
|
+
|
|
202
|
+
if (retrieved !== testValue) {
|
|
203
|
+
checks.passed = false;
|
|
204
|
+
checks.details.readWrite = 'Read/write test failed';
|
|
205
|
+
} else {
|
|
206
|
+
checks.details.readWrite = 'OK';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Check 5: Test sorted set operations
|
|
210
|
+
const testZSetKey = 'boss:healthcheck:zset';
|
|
211
|
+
await client.zadd(testZSetKey, 100, 'test_member');
|
|
212
|
+
const score = await client.zscore(testZSetKey, 'test_member');
|
|
213
|
+
await client.del(testZSetKey);
|
|
214
|
+
|
|
215
|
+
if (score !== '100') {
|
|
216
|
+
checks.passed = false;
|
|
217
|
+
checks.details.sortedSets = 'Sorted set test failed';
|
|
218
|
+
} else {
|
|
219
|
+
checks.details.sortedSets = 'OK';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
} catch (error) {
|
|
223
|
+
checks.passed = false;
|
|
224
|
+
checks.details.error = error.message;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return checks;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get current Redis statistics
|
|
232
|
+
*
|
|
233
|
+
* @param {string} redisUrl - Redis connection string
|
|
234
|
+
* @returns {Promise<Object>} Redis statistics
|
|
235
|
+
*/
|
|
236
|
+
export async function getRedisStats(redisUrl) {
|
|
237
|
+
const client = new Redis(redisUrl);
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
await client.ping();
|
|
241
|
+
|
|
242
|
+
const stats = {
|
|
243
|
+
identity: null,
|
|
244
|
+
totalSessions: 0,
|
|
245
|
+
totalRepos: 0,
|
|
246
|
+
activeSessions: 0,
|
|
247
|
+
leaderboardSize: 0,
|
|
248
|
+
achievements: {},
|
|
249
|
+
cacheKeys: 0
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Get identity
|
|
253
|
+
const identityData = await client.get('boss:identity');
|
|
254
|
+
if (identityData) {
|
|
255
|
+
stats.identity = JSON.parse(identityData);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Count sessions in history
|
|
259
|
+
stats.totalSessions = await client.zcard('boss:sessions:history');
|
|
260
|
+
|
|
261
|
+
// Count repos
|
|
262
|
+
const repoKeys = await client.keys('boss:repo:*');
|
|
263
|
+
stats.totalRepos = repoKeys.length;
|
|
264
|
+
|
|
265
|
+
// Count active sessions
|
|
266
|
+
const activeSessionKeys = await client.keys('boss:session:*:current');
|
|
267
|
+
stats.activeSessions = activeSessionKeys.length;
|
|
268
|
+
|
|
269
|
+
// Get leaderboard size
|
|
270
|
+
stats.leaderboardSize = await client.zcard('boss:leaderboard:xp');
|
|
271
|
+
|
|
272
|
+
// Count cache keys
|
|
273
|
+
const cacheKeys = await client.keys('boss:cache:*');
|
|
274
|
+
stats.cacheKeys = cacheKeys.length;
|
|
275
|
+
|
|
276
|
+
// Get achievements for all users
|
|
277
|
+
const achievementKeys = await client.keys('boss:achievements:*');
|
|
278
|
+
for (const key of achievementKeys) {
|
|
279
|
+
const username = key.replace('boss:achievements:', '');
|
|
280
|
+
const achievements = await client.smembers(key);
|
|
281
|
+
stats.achievements[username] = achievements.filter(a => a !== '__init__');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return stats;
|
|
285
|
+
|
|
286
|
+
} catch (error) {
|
|
287
|
+
throw new Error(`Failed to get Redis stats: ${error.message}`);
|
|
288
|
+
} finally {
|
|
289
|
+
await client.quit();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Reset Redis to initial state (WARNING: Destructive!)
|
|
295
|
+
*
|
|
296
|
+
* @param {string} redisUrl - Redis connection string
|
|
297
|
+
* @param {string} username - GitHub username
|
|
298
|
+
* @returns {Promise<void>}
|
|
299
|
+
*/
|
|
300
|
+
export async function resetRedis(redisUrl, username = 'default') {
|
|
301
|
+
const client = new Redis(redisUrl);
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
await client.ping();
|
|
305
|
+
|
|
306
|
+
// Delete all Boss Claude keys
|
|
307
|
+
const allKeys = await client.keys('boss:*');
|
|
308
|
+
|
|
309
|
+
if (allKeys.length > 0) {
|
|
310
|
+
await client.del(...allKeys);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Re-initialize
|
|
314
|
+
await client.quit();
|
|
315
|
+
return await initializeRedis(redisUrl, username, true);
|
|
316
|
+
|
|
317
|
+
} catch (error) {
|
|
318
|
+
throw new Error(`Failed to reset Redis: ${error.message}`);
|
|
319
|
+
} finally {
|
|
320
|
+
if (client.status === 'ready') {
|
|
321
|
+
await client.quit();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Verify Redis connection and structure
|
|
328
|
+
*
|
|
329
|
+
* @param {string} redisUrl - Redis connection string
|
|
330
|
+
* @returns {Promise<Object>} Verification results
|
|
331
|
+
*/
|
|
332
|
+
export async function verifyRedis(redisUrl) {
|
|
333
|
+
const client = new Redis(redisUrl);
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
// Test connection
|
|
337
|
+
await client.ping();
|
|
338
|
+
|
|
339
|
+
// Get server info
|
|
340
|
+
const serverInfo = await client.info('server');
|
|
341
|
+
const redisVersion = serverInfo.match(/redis_version:(.+)/)?.[1]?.trim();
|
|
342
|
+
|
|
343
|
+
// Perform health check
|
|
344
|
+
const healthCheck = await performHealthCheck(client);
|
|
345
|
+
|
|
346
|
+
// Get key counts
|
|
347
|
+
const identityExists = await client.exists('boss:identity');
|
|
348
|
+
const historySize = await client.zcard('boss:sessions:history');
|
|
349
|
+
const leaderboardSize = await client.zcard('boss:leaderboard:xp');
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
connected: true,
|
|
353
|
+
version: redisVersion,
|
|
354
|
+
healthCheck,
|
|
355
|
+
structures: {
|
|
356
|
+
identity: identityExists === 1,
|
|
357
|
+
sessionHistory: historySize,
|
|
358
|
+
leaderboard: leaderboardSize
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
} catch (error) {
|
|
363
|
+
return {
|
|
364
|
+
connected: false,
|
|
365
|
+
error: error.message
|
|
366
|
+
};
|
|
367
|
+
} finally {
|
|
368
|
+
await client.quit();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Print formatted initialization results
|
|
374
|
+
*
|
|
375
|
+
* @param {Object} results - Results from initializeRedis
|
|
376
|
+
* @param {string} username - GitHub username
|
|
377
|
+
*/
|
|
378
|
+
export function printInitResults(results, username) {
|
|
379
|
+
console.log(chalk.cyan('\nš¦ Redis Initialization Results\n'));
|
|
380
|
+
|
|
381
|
+
// Identity
|
|
382
|
+
if (results.identity.created) {
|
|
383
|
+
console.log(chalk.green('ā boss:identity') + chalk.dim(' - Created default identity'));
|
|
384
|
+
} else if (results.identity.existed) {
|
|
385
|
+
console.log(chalk.yellow('ā boss:identity') + chalk.dim(' - Already exists (preserved)'));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Session History
|
|
389
|
+
if (results.history.created) {
|
|
390
|
+
console.log(chalk.green('ā boss:sessions:history') + chalk.dim(' - Initialized sorted set'));
|
|
391
|
+
} else if (results.history.existed) {
|
|
392
|
+
console.log(chalk.yellow('ā boss:sessions:history') + chalk.dim(' - Already exists'));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Leaderboard
|
|
396
|
+
if (results.leaderboard.created) {
|
|
397
|
+
console.log(chalk.green(`ā boss:leaderboard:xp`) + chalk.dim(` - Added ${username} with 0 XP`));
|
|
398
|
+
} else if (results.leaderboard.existed) {
|
|
399
|
+
console.log(chalk.yellow('ā boss:leaderboard:xp') + chalk.dim(' - Already exists'));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Achievements
|
|
403
|
+
if (results.achievements.created) {
|
|
404
|
+
console.log(chalk.green(`ā boss:achievements:${username}`) + chalk.dim(' - Initialized empty set'));
|
|
405
|
+
} else if (results.achievements.existed) {
|
|
406
|
+
console.log(chalk.yellow(`ā boss:achievements:${username}`) + chalk.dim(' - Already exists'));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Health Check
|
|
410
|
+
console.log();
|
|
411
|
+
if (results.healthCheck.passed) {
|
|
412
|
+
console.log(chalk.green('ā Health Check Passed') + chalk.dim(' - All structures validated'));
|
|
413
|
+
} else {
|
|
414
|
+
console.log(chalk.red('ā Health Check Failed'));
|
|
415
|
+
Object.entries(results.healthCheck.details).forEach(([key, value]) => {
|
|
416
|
+
if (value !== 'OK') {
|
|
417
|
+
console.log(chalk.red(` ā ${key}: `) + chalk.dim(value));
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
console.log();
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Integration point for setup wizard
|
|
427
|
+
* Called automatically after Redis connection is validated
|
|
428
|
+
*
|
|
429
|
+
* @param {string} redisUrl - Redis connection string
|
|
430
|
+
* @param {string} username - GitHub username
|
|
431
|
+
* @returns {Promise<boolean>} Success status
|
|
432
|
+
*/
|
|
433
|
+
export async function setupRedisForWizard(redisUrl, username) {
|
|
434
|
+
try {
|
|
435
|
+
console.log(chalk.cyan('\nš§ Initializing Redis data structures...\n'));
|
|
436
|
+
|
|
437
|
+
const results = await initializeRedis(redisUrl, username, false);
|
|
438
|
+
printInitResults(results, username);
|
|
439
|
+
|
|
440
|
+
if (!results.healthCheck.passed) {
|
|
441
|
+
console.log(chalk.yellow('\nā ļø Warning: Health check failed. Some features may not work correctly.'));
|
|
442
|
+
console.log(chalk.dim('You can try running: boss-claude redis:reset\n'));
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
console.log(chalk.green('ā Redis initialization complete!\n'));
|
|
447
|
+
return true;
|
|
448
|
+
|
|
449
|
+
} catch (error) {
|
|
450
|
+
console.log(chalk.red(`\nā Redis initialization failed: ${error.message}\n`));
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Export constants for use in other modules
|
|
456
|
+
export { DEFAULT_IDENTITY, ACHIEVEMENTS };
|