@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,492 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Boss Claude Setup Wizard
|
|
5
|
+
* Interactive setup flow for first-time installation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
import Redis from 'ioredis';
|
|
13
|
+
import pg from 'pg';
|
|
14
|
+
import { Octokit } from '@octokit/rest';
|
|
15
|
+
import {
|
|
16
|
+
header,
|
|
17
|
+
ask,
|
|
18
|
+
askSecret,
|
|
19
|
+
confirm,
|
|
20
|
+
spinner,
|
|
21
|
+
success,
|
|
22
|
+
error,
|
|
23
|
+
warning,
|
|
24
|
+
info,
|
|
25
|
+
box,
|
|
26
|
+
pause,
|
|
27
|
+
clear
|
|
28
|
+
} from './prompts.js';
|
|
29
|
+
|
|
30
|
+
const { Pool } = pg;
|
|
31
|
+
|
|
32
|
+
// Configuration
|
|
33
|
+
const BOSS_DIR = join(os.homedir(), '.boss-claude');
|
|
34
|
+
const ENV_FILE = join(BOSS_DIR, '.env');
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Main setup wizard
|
|
38
|
+
*/
|
|
39
|
+
async function runSetup() {
|
|
40
|
+
clear();
|
|
41
|
+
|
|
42
|
+
// Welcome screen
|
|
43
|
+
header(
|
|
44
|
+
'🎮 BOSS CLAUDE SETUP WIZARD',
|
|
45
|
+
'Let\'s get you set up with your AI automation boss!'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
box(
|
|
49
|
+
'Boss Claude is a gamified AI assistant that tracks your\n' +
|
|
50
|
+
'progress across all your projects. You earn XP, level up,\n' +
|
|
51
|
+
'and build a token bank as you work with Claude.\n\n' +
|
|
52
|
+
'This wizard will help you configure:\n' +
|
|
53
|
+
' • GitHub integration (for session memory)\n' +
|
|
54
|
+
' • Redis (for real-time stats)\n' +
|
|
55
|
+
' • PostgreSQL (for advanced analytics)',
|
|
56
|
+
'Welcome'
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const shouldContinue = await confirm('\nReady to begin setup?', true);
|
|
60
|
+
|
|
61
|
+
if (!shouldContinue) {
|
|
62
|
+
console.log(chalk.yellow('\nSetup cancelled. Run "boss-claude setup" when ready!\n'));
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Create .boss-claude directory
|
|
67
|
+
if (!existsSync(BOSS_DIR)) {
|
|
68
|
+
mkdirSync(BOSS_DIR, { recursive: true });
|
|
69
|
+
success(`Created ${BOSS_DIR}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const config = {};
|
|
73
|
+
|
|
74
|
+
// Step 1: GitHub Token
|
|
75
|
+
await setupGitHub(config);
|
|
76
|
+
|
|
77
|
+
// Step 2: Redis
|
|
78
|
+
await setupRedis(config);
|
|
79
|
+
|
|
80
|
+
// Step 3: PostgreSQL
|
|
81
|
+
await setupPostgreSQL(config);
|
|
82
|
+
|
|
83
|
+
// Step 4: Save configuration
|
|
84
|
+
await saveConfig(config);
|
|
85
|
+
|
|
86
|
+
// Step 5: Test everything
|
|
87
|
+
await testConfiguration(config);
|
|
88
|
+
|
|
89
|
+
// Success!
|
|
90
|
+
showSuccessScreen();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Setup GitHub integration
|
|
95
|
+
*/
|
|
96
|
+
async function setupGitHub(config) {
|
|
97
|
+
header('Step 1: GitHub Integration', 'Boss Claude uses GitHub Issues to store session memories');
|
|
98
|
+
|
|
99
|
+
info('Why GitHub?');
|
|
100
|
+
console.log(chalk.dim(' • Sessions are stored as searchable GitHub Issues'));
|
|
101
|
+
console.log(chalk.dim(' • Works across all your repositories'));
|
|
102
|
+
console.log(chalk.dim(' • Free and reliable long-term storage\n'));
|
|
103
|
+
|
|
104
|
+
const hasToken = await confirm('Do you already have a GitHub Personal Access Token?', false);
|
|
105
|
+
|
|
106
|
+
if (!hasToken) {
|
|
107
|
+
box(
|
|
108
|
+
'Creating a GitHub Token:\n\n' +
|
|
109
|
+
'1. Go to: https://github.com/settings/tokens/new\n' +
|
|
110
|
+
'2. Note: "Boss Claude Session Memory"\n' +
|
|
111
|
+
'3. Scopes needed: repo (full control)\n' +
|
|
112
|
+
'4. Click "Generate token"\n' +
|
|
113
|
+
'5. Copy the token (it won\'t be shown again!)',
|
|
114
|
+
'Instructions'
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
await pause();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get GitHub token
|
|
121
|
+
const githubToken = await askSecret('\nEnter your GitHub Personal Access Token');
|
|
122
|
+
|
|
123
|
+
if (!githubToken) {
|
|
124
|
+
error('GitHub token is required');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Validate token
|
|
129
|
+
const githubResult = await spinner('Validating GitHub token', async () => {
|
|
130
|
+
const octokit = new Octokit({ auth: githubToken });
|
|
131
|
+
const { data: user } = await octokit.users.getAuthenticated();
|
|
132
|
+
return user;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (!githubResult.success) {
|
|
136
|
+
error('Failed to validate GitHub token', githubResult.error.message);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
success(`Authenticated as ${chalk.cyan(githubResult.result.login)}`);
|
|
141
|
+
|
|
142
|
+
config.GITHUB_TOKEN = githubToken;
|
|
143
|
+
config.GITHUB_USER = githubResult.result.login;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Setup Redis connection
|
|
148
|
+
*/
|
|
149
|
+
async function setupRedis(config) {
|
|
150
|
+
header('Step 2: Redis Configuration', 'Redis stores real-time stats and session data');
|
|
151
|
+
|
|
152
|
+
info('Why Redis?');
|
|
153
|
+
console.log(chalk.dim(' • Fast real-time updates'));
|
|
154
|
+
console.log(chalk.dim(' • Efficient for frequently accessed data'));
|
|
155
|
+
console.log(chalk.dim(' • Great for leaderboards and stats\n'));
|
|
156
|
+
|
|
157
|
+
const hasRedis = await confirm('Do you have a Redis instance?', false);
|
|
158
|
+
|
|
159
|
+
if (!hasRedis) {
|
|
160
|
+
box(
|
|
161
|
+
'Free Redis Options:\n\n' +
|
|
162
|
+
'1. Railway.app - redis.new (easiest!)\n' +
|
|
163
|
+
'2. Redis Cloud - redis.com/try-free\n' +
|
|
164
|
+
'3. Upstash - upstash.com (serverless)\n' +
|
|
165
|
+
'4. Local - brew install redis (macOS)\n\n' +
|
|
166
|
+
'Connection string format:\n' +
|
|
167
|
+
'redis://username:password@host:port',
|
|
168
|
+
'Get Redis'
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const setupLater = await confirm('\nWould you like to skip Redis for now?', false);
|
|
172
|
+
|
|
173
|
+
if (setupLater) {
|
|
174
|
+
warning('Skipping Redis. You can add it later by editing ~/.boss-claude/.env');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await pause();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Get Redis URL
|
|
182
|
+
const redisUrl = await ask('\nEnter Redis connection string', 'redis://localhost:6379');
|
|
183
|
+
|
|
184
|
+
// Validate Redis
|
|
185
|
+
const redisResult = await spinner('Testing Redis connection', async () => {
|
|
186
|
+
const client = new Redis(redisUrl);
|
|
187
|
+
await client.ping();
|
|
188
|
+
const info = await client.info('server');
|
|
189
|
+
await client.quit();
|
|
190
|
+
return info;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (!redisResult.success) {
|
|
194
|
+
error('Failed to connect to Redis', redisResult.error.message);
|
|
195
|
+
|
|
196
|
+
const skipRedis = await confirm('\nContinue without Redis?', true);
|
|
197
|
+
if (!skipRedis) {
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
warning('Continuing without Redis. Some features will be limited.');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
success('Redis connection successful');
|
|
205
|
+
config.REDIS_URL = redisUrl;
|
|
206
|
+
|
|
207
|
+
// Initialize Redis data structures
|
|
208
|
+
const { setupRedisForWizard } = await import('../lib/setup/init-redis.js');
|
|
209
|
+
const initSuccess = await setupRedisForWizard(redisUrl, config.GITHUB_USER || 'default');
|
|
210
|
+
|
|
211
|
+
if (!initSuccess) {
|
|
212
|
+
const continueAnyway = await confirm('\nContinue with incomplete Redis setup?', true);
|
|
213
|
+
if (!continueAnyway) {
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Setup PostgreSQL connection
|
|
221
|
+
*/
|
|
222
|
+
async function setupPostgreSQL(config) {
|
|
223
|
+
header('Step 3: PostgreSQL Database', 'PostgreSQL provides advanced analytics and insights');
|
|
224
|
+
|
|
225
|
+
info('Why PostgreSQL?');
|
|
226
|
+
console.log(chalk.dim(' • Advanced session analytics'));
|
|
227
|
+
console.log(chalk.dim(' • Achievement tracking'));
|
|
228
|
+
console.log(chalk.dim(' • Historical data and trends\n'));
|
|
229
|
+
|
|
230
|
+
const hasPostgres = await confirm('Do you have a PostgreSQL database?', false);
|
|
231
|
+
|
|
232
|
+
if (!hasPostgres) {
|
|
233
|
+
box(
|
|
234
|
+
'Free PostgreSQL Options:\n\n' +
|
|
235
|
+
'1. Railway.app - railway.app (recommended!)\n' +
|
|
236
|
+
'2. Supabase - supabase.com (includes UI)\n' +
|
|
237
|
+
'3. Neon - neon.tech (serverless)\n' +
|
|
238
|
+
'4. Local - brew install postgresql (macOS)\n\n' +
|
|
239
|
+
'Connection string format:\n' +
|
|
240
|
+
'postgresql://user:pass@host:port/database',
|
|
241
|
+
'Get PostgreSQL'
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const setupLater = await confirm('\nWould you like to skip PostgreSQL for now?', false);
|
|
245
|
+
|
|
246
|
+
if (setupLater) {
|
|
247
|
+
warning('Skipping PostgreSQL. Basic features will still work.');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
await pause();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Get PostgreSQL URL
|
|
255
|
+
const postgresUrl = await ask('\nEnter PostgreSQL connection string');
|
|
256
|
+
|
|
257
|
+
if (!postgresUrl) {
|
|
258
|
+
warning('Skipping PostgreSQL. You can add it later.');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Validate PostgreSQL
|
|
263
|
+
const pgResult = await spinner('Testing PostgreSQL connection', async () => {
|
|
264
|
+
const pool = new Pool({
|
|
265
|
+
connectionString: postgresUrl,
|
|
266
|
+
ssl: { rejectUnauthorized: false }
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const result = await pool.query('SELECT version()');
|
|
270
|
+
await pool.end();
|
|
271
|
+
return result.rows[0].version;
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
if (!pgResult.success) {
|
|
275
|
+
error('Failed to connect to PostgreSQL', pgResult.error.message);
|
|
276
|
+
|
|
277
|
+
const skipPg = await confirm('\nContinue without PostgreSQL?', true);
|
|
278
|
+
if (!skipPg) {
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
warning('Continuing without PostgreSQL. Some features will be limited.');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
success('PostgreSQL connection successful');
|
|
286
|
+
config.BOSS_CLAUDE_PG_URL = postgresUrl;
|
|
287
|
+
|
|
288
|
+
// Ask about schema setup
|
|
289
|
+
const shouldSetupSchema = await confirm('\nWould you like to set up the database schema now?', true);
|
|
290
|
+
|
|
291
|
+
if (shouldSetupSchema) {
|
|
292
|
+
await setupDatabaseSchema(postgresUrl);
|
|
293
|
+
} else {
|
|
294
|
+
info('You can set up the schema later by running: boss-claude db:setup');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Setup database schema
|
|
300
|
+
*/
|
|
301
|
+
async function setupDatabaseSchema(postgresUrl) {
|
|
302
|
+
const schemaResult = await spinner('Creating database schema', async () => {
|
|
303
|
+
const pool = new Pool({
|
|
304
|
+
connectionString: postgresUrl,
|
|
305
|
+
ssl: { rejectUnauthorized: false }
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Create schema
|
|
309
|
+
await pool.query('CREATE SCHEMA IF NOT EXISTS boss_claude');
|
|
310
|
+
|
|
311
|
+
// Create sessions table
|
|
312
|
+
await pool.query(`
|
|
313
|
+
CREATE TABLE IF NOT EXISTS boss_claude.sessions (
|
|
314
|
+
id SERIAL PRIMARY KEY,
|
|
315
|
+
user_id TEXT NOT NULL,
|
|
316
|
+
project TEXT NOT NULL,
|
|
317
|
+
start_time TIMESTAMP DEFAULT NOW(),
|
|
318
|
+
end_time TIMESTAMP,
|
|
319
|
+
duration_seconds INTEGER GENERATED ALWAYS AS (
|
|
320
|
+
EXTRACT(EPOCH FROM (end_time - start_time))::INTEGER
|
|
321
|
+
) STORED,
|
|
322
|
+
level_at_start INTEGER DEFAULT 1,
|
|
323
|
+
level_at_end INTEGER,
|
|
324
|
+
xp_earned INTEGER DEFAULT 0,
|
|
325
|
+
tokens_saved INTEGER DEFAULT 0,
|
|
326
|
+
tasks_completed INTEGER DEFAULT 0,
|
|
327
|
+
perfect_executions INTEGER DEFAULT 0,
|
|
328
|
+
efficiency_multiplier DECIMAL(3,2) DEFAULT 1.0,
|
|
329
|
+
summary TEXT,
|
|
330
|
+
context_data JSONB
|
|
331
|
+
)
|
|
332
|
+
`);
|
|
333
|
+
|
|
334
|
+
// Create achievements table
|
|
335
|
+
await pool.query(`
|
|
336
|
+
CREATE TABLE IF NOT EXISTS boss_claude.achievements (
|
|
337
|
+
id SERIAL PRIMARY KEY,
|
|
338
|
+
user_id TEXT NOT NULL,
|
|
339
|
+
achievement_type TEXT NOT NULL,
|
|
340
|
+
achievement_name TEXT NOT NULL,
|
|
341
|
+
description TEXT,
|
|
342
|
+
xp_reward INTEGER DEFAULT 0,
|
|
343
|
+
metadata JSONB,
|
|
344
|
+
earned_at TIMESTAMP DEFAULT NOW()
|
|
345
|
+
)
|
|
346
|
+
`);
|
|
347
|
+
|
|
348
|
+
// Create memory_snapshots table
|
|
349
|
+
await pool.query(`
|
|
350
|
+
CREATE TABLE IF NOT EXISTS boss_claude.memory_snapshots (
|
|
351
|
+
id SERIAL PRIMARY KEY,
|
|
352
|
+
user_id TEXT NOT NULL,
|
|
353
|
+
session_id INTEGER REFERENCES boss_claude.sessions(id),
|
|
354
|
+
snapshot_type TEXT NOT NULL,
|
|
355
|
+
snapshot_data JSONB NOT NULL,
|
|
356
|
+
level INTEGER,
|
|
357
|
+
token_bank INTEGER,
|
|
358
|
+
total_xp INTEGER,
|
|
359
|
+
efficiency DECIMAL(3,2),
|
|
360
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
361
|
+
)
|
|
362
|
+
`);
|
|
363
|
+
|
|
364
|
+
// Create indexes
|
|
365
|
+
await pool.query('CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON boss_claude.sessions(user_id)');
|
|
366
|
+
await pool.query('CREATE INDEX IF NOT EXISTS idx_sessions_project ON boss_claude.sessions(project)');
|
|
367
|
+
await pool.query('CREATE INDEX IF NOT EXISTS idx_achievements_user_id ON boss_claude.achievements(user_id)');
|
|
368
|
+
|
|
369
|
+
await pool.end();
|
|
370
|
+
return true;
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
if (schemaResult.success) {
|
|
374
|
+
success('Database schema created successfully');
|
|
375
|
+
} else {
|
|
376
|
+
error('Failed to create database schema', schemaResult.error.message);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Save configuration to .env file
|
|
382
|
+
*/
|
|
383
|
+
async function saveConfig(config) {
|
|
384
|
+
header('Saving Configuration', 'Writing settings to ~/.boss-claude/.env');
|
|
385
|
+
|
|
386
|
+
const envContent = Object.entries(config)
|
|
387
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
388
|
+
.join('\n') + '\n';
|
|
389
|
+
|
|
390
|
+
await spinner('Saving configuration', async () => {
|
|
391
|
+
writeFileSync(ENV_FILE, envContent, 'utf-8');
|
|
392
|
+
return true;
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
success(`Configuration saved to ${ENV_FILE}`);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Test full configuration
|
|
400
|
+
*/
|
|
401
|
+
async function testConfiguration(config) {
|
|
402
|
+
header('Testing Configuration', 'Verifying all connections');
|
|
403
|
+
|
|
404
|
+
const tests = [];
|
|
405
|
+
|
|
406
|
+
// Test GitHub
|
|
407
|
+
if (config.GITHUB_TOKEN) {
|
|
408
|
+
tests.push({
|
|
409
|
+
name: 'GitHub Authentication',
|
|
410
|
+
test: async () => {
|
|
411
|
+
const octokit = new Octokit({ auth: config.GITHUB_TOKEN });
|
|
412
|
+
await octokit.users.getAuthenticated();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Test Redis
|
|
418
|
+
if (config.REDIS_URL) {
|
|
419
|
+
tests.push({
|
|
420
|
+
name: 'Redis Connection',
|
|
421
|
+
test: async () => {
|
|
422
|
+
const client = new Redis(config.REDIS_URL);
|
|
423
|
+
await client.ping();
|
|
424
|
+
await client.quit();
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Test PostgreSQL
|
|
430
|
+
if (config.BOSS_CLAUDE_PG_URL) {
|
|
431
|
+
tests.push({
|
|
432
|
+
name: 'PostgreSQL Connection',
|
|
433
|
+
test: async () => {
|
|
434
|
+
const pool = new Pool({
|
|
435
|
+
connectionString: config.BOSS_CLAUDE_PG_URL,
|
|
436
|
+
ssl: { rejectUnauthorized: false }
|
|
437
|
+
});
|
|
438
|
+
await pool.query('SELECT 1');
|
|
439
|
+
await pool.end();
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Run all tests
|
|
445
|
+
for (const test of tests) {
|
|
446
|
+
const result = await spinner(test.name, test.test);
|
|
447
|
+
if (!result.success) {
|
|
448
|
+
error(`${test.name} failed`, result.error.message);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Show success screen
|
|
455
|
+
*/
|
|
456
|
+
function showSuccessScreen() {
|
|
457
|
+
clear();
|
|
458
|
+
|
|
459
|
+
header('🎉 Setup Complete!', 'Boss Claude is ready to go!');
|
|
460
|
+
|
|
461
|
+
box(
|
|
462
|
+
'You\'re all set! Here\'s how to get started:\n\n' +
|
|
463
|
+
'1. Run "boss-claude init" in any git repository\n' +
|
|
464
|
+
'2. Use "boss-claude status" to check your stats\n' +
|
|
465
|
+
'3. Use "boss-claude save" to save sessions\n' +
|
|
466
|
+
'4. Use "boss-claude recall" to search memories\n\n' +
|
|
467
|
+
'Boss Claude will auto-load in Claude Code and\n' +
|
|
468
|
+
'track your progress across all projects.',
|
|
469
|
+
'Next Steps'
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
success('Happy coding with Boss Claude!');
|
|
473
|
+
|
|
474
|
+
console.log(chalk.dim('\n💡 Tip: Add this to your project\'s CLAUDE.md:'));
|
|
475
|
+
box(
|
|
476
|
+
'# BOSS CLAUDE AUTO-LOAD\n' +
|
|
477
|
+
'```javascript\n' +
|
|
478
|
+
'import { formatStatusForClaude } from \'@cpretzinger/boss-claude/lib/init.js\';\n' +
|
|
479
|
+
'console.log(await formatStatusForClaude());\n' +
|
|
480
|
+
'```',
|
|
481
|
+
''
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
console.log();
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Run setup
|
|
488
|
+
runSetup().catch((err) => {
|
|
489
|
+
console.error(chalk.red('\n❌ Setup failed:'), err.message);
|
|
490
|
+
console.error(chalk.dim(err.stack));
|
|
491
|
+
process.exit(1);
|
|
492
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Boss Claude Configuration
|
|
2
|
+
# Copy this file to ~/.boss-claude/.env and fill in your credentials
|
|
3
|
+
|
|
4
|
+
# Redis URL (required) - For Boss identity and session storage
|
|
5
|
+
REDIS_URL=redis://default:password@host:port
|
|
6
|
+
|
|
7
|
+
# GitHub Token (required) - For memory storage in GitHub Issues
|
|
8
|
+
# Create at: https://github.com/settings/tokens
|
|
9
|
+
# Needs: repo scope
|
|
10
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
11
|
+
|
|
12
|
+
# GitHub Owner (optional) - Defaults to 'cpretzinger'
|
|
13
|
+
GITHUB_OWNER=cpretzinger
|
|
14
|
+
|
|
15
|
+
# GitHub Memory Repository (optional) - Defaults to 'boss-claude-memory'
|
|
16
|
+
# This repo will store all your session memories as GitHub Issues
|
|
17
|
+
GITHUB_MEMORY_REPO=boss-claude-memory
|
package/lib/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Boss Claude Libraries
|
|
2
|
+
|
|
3
|
+
Reusable modules for the Boss Claude CLI system.
|
|
4
|
+
|
|
5
|
+
## Available Libraries
|
|
6
|
+
|
|
7
|
+
### prompts.js - Interactive CLI Prompts
|
|
8
|
+
|
|
9
|
+
Beautiful, validated prompt system with colors and spinners.
|
|
10
|
+
|
|
11
|
+
**Quick Start:**
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import prompts from './lib/prompts.js';
|
|
15
|
+
|
|
16
|
+
const name = await prompts.promptText({
|
|
17
|
+
message: 'Your name?',
|
|
18
|
+
validate: prompts.validators.required
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
prompts.success('Welcome, ' + name + '!');
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Features:**
|
|
25
|
+
- Text, password, number input
|
|
26
|
+
- Select, multi-select
|
|
27
|
+
- Confirmations
|
|
28
|
+
- Built-in validators
|
|
29
|
+
- Beautiful colors and themes
|
|
30
|
+
- Loading spinners
|
|
31
|
+
- Progress indicators
|
|
32
|
+
- Preset prompt sequences
|
|
33
|
+
|
|
34
|
+
**Documentation:** See `/docs/PROMPTS.md`
|
|
35
|
+
|
|
36
|
+
**Examples:**
|
|
37
|
+
- `/examples/quick-test.js` - Simple test
|
|
38
|
+
- `/examples/prompts-demo.js` - Full demo
|
|
39
|
+
- `/examples/setup-wizard.js` - Real-world usage
|
|
40
|
+
|
|
41
|
+
**Run Examples:**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run demo:quick # Quick test
|
|
45
|
+
npm run demo:prompts # Full demo
|
|
46
|
+
npm run demo:wizard # Setup wizard
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Creating New Libraries
|
|
50
|
+
|
|
51
|
+
1. Create `/lib/your-library.js`
|
|
52
|
+
2. Export functions/objects
|
|
53
|
+
3. Add documentation to `/docs/YOUR-LIBRARY.md`
|
|
54
|
+
4. Create examples in `/examples/`
|
|
55
|
+
5. Update this README
|
|
56
|
+
|
|
57
|
+
## Library Standards
|
|
58
|
+
|
|
59
|
+
- Use ES modules (`import`/`export`)
|
|
60
|
+
- Document all public functions
|
|
61
|
+
- Include JSDoc comments
|
|
62
|
+
- Provide usage examples
|
|
63
|
+
- Handle errors gracefully
|
|
64
|
+
- Use consistent naming
|
|
65
|
+
- Export default + named exports
|
|
66
|
+
|
|
67
|
+
## Testing Libraries
|
|
68
|
+
|
|
69
|
+
Create test files in `/examples/` that demonstrate:
|
|
70
|
+
- Basic usage
|
|
71
|
+
- Error handling
|
|
72
|
+
- Edge cases
|
|
73
|
+
- Integration with other libraries
|
|
74
|
+
|
|
75
|
+
## Dependencies
|
|
76
|
+
|
|
77
|
+
Libraries can use:
|
|
78
|
+
- inquirer (prompts)
|
|
79
|
+
- chalk (colors)
|
|
80
|
+
- ora (spinners)
|
|
81
|
+
- ioredis (Redis)
|
|
82
|
+
- pg (PostgreSQL)
|
|
83
|
+
- commander (CLI)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
|
|
5
|
+
const BOSS_DIR = join(os.homedir(), '.boss-claude');
|
|
6
|
+
const LOG_FILE = join(BOSS_DIR, 'agent-activity.log');
|
|
7
|
+
|
|
8
|
+
// Ensure directory exists
|
|
9
|
+
try {
|
|
10
|
+
mkdirSync(BOSS_DIR, { recursive: true });
|
|
11
|
+
} catch (err) {
|
|
12
|
+
// Directory already exists
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Log agent activity to ~/.boss-claude/agent-activity.log
|
|
17
|
+
* @param {string} event - Event type (start, complete, error)
|
|
18
|
+
* @param {string} agent - Agent name
|
|
19
|
+
* @param {string} details - Additional details
|
|
20
|
+
*/
|
|
21
|
+
export function logAgentActivity(event, agent, details = '') {
|
|
22
|
+
const timestamp = new Date().toISOString();
|
|
23
|
+
const logLine = `[${timestamp}] ${event.toUpperCase()}: ${agent}${details ? ' - ' + details : ''}\n`;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
appendFileSync(LOG_FILE, logLine, 'utf8');
|
|
27
|
+
} catch (err) {
|
|
28
|
+
// Silent fail - don't crash if logging fails
|
|
29
|
+
console.error(`Failed to write agent log: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Log Task agent start
|
|
35
|
+
* @param {string} taskDescription - Description of the task
|
|
36
|
+
*/
|
|
37
|
+
export function logTaskStart(taskDescription) {
|
|
38
|
+
logAgentActivity('start', 'Task', taskDescription);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Log Task agent completion
|
|
43
|
+
* @param {string} taskDescription - Description of the task
|
|
44
|
+
* @param {boolean} success - Whether task succeeded
|
|
45
|
+
*/
|
|
46
|
+
export function logTaskComplete(taskDescription, success = true) {
|
|
47
|
+
const status = success ? 'SUCCESS' : 'FAILED';
|
|
48
|
+
logAgentActivity('complete', 'Task', `${taskDescription} [${status}]`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Log any agent activity
|
|
53
|
+
* @param {string} agentName - Name of the agent
|
|
54
|
+
* @param {string} action - Action being performed
|
|
55
|
+
* @param {string} details - Additional details
|
|
56
|
+
*/
|
|
57
|
+
export function logAgent(agentName, action, details = '') {
|
|
58
|
+
logAgentActivity(action, agentName, details);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { LOG_FILE };
|