@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,156 @@
1
+ #!/bin/bash
2
+
3
+ ###############################################################################
4
+ # GRACEFUL SHUTDOWN SCRIPT
5
+ # Purpose: Terminate all background boss-claude agents with 10-minute timeout
6
+ # Features: Graceful SIGTERM first, then force kill after timeout
7
+ ###############################################################################
8
+
9
+ set -e
10
+
11
+ TIMEOUT_SECONDS=600 # 10 minutes
12
+ POLL_INTERVAL=5 # Check every 5 seconds
13
+ LOG_FILE="/tmp/boss-claude-shutdown-$(date +%Y%m%d-%H%M%S).log"
14
+
15
+ echo "========================================" | tee "$LOG_FILE"
16
+ echo "GRACEFUL SHUTDOWN - $(date)" | tee -a "$LOG_FILE"
17
+ echo "========================================" | tee -a "$LOG_FILE"
18
+
19
+ # Function to log with timestamp
20
+ log() {
21
+ echo "[$(date '+%H:%M:%S')] $1" | tee -a "$LOG_FILE"
22
+ }
23
+
24
+ # Function to get all boss-claude related PIDs
25
+ get_boss_pids() {
26
+ ps aux | grep -E "(boss-claude|bin/boss-claude)" | grep -v grep | grep -v "graceful-shutdown" | awk '{print $2}' || true
27
+ }
28
+
29
+ # Step 1: Identify all running processes
30
+ log "Step 1: Identifying all boss-claude processes..."
31
+ INITIAL_PIDS=$(get_boss_pids)
32
+
33
+ if [ -z "$INITIAL_PIDS" ]; then
34
+ log "✅ No boss-claude processes found. System is clean."
35
+ exit 0
36
+ fi
37
+
38
+ INITIAL_COUNT=$(echo "$INITIAL_PIDS" | wc -l | tr -d ' ')
39
+ log "Found $INITIAL_COUNT boss-claude processes:"
40
+ echo "$INITIAL_PIDS" | while read pid; do
41
+ process_info=$(ps -p "$pid" -o pid,etime,command | tail -n 1)
42
+ log " PID $pid: $process_info"
43
+ done
44
+
45
+ # Step 2: Send SIGTERM to all processes
46
+ log ""
47
+ log "Step 2: Sending SIGTERM (graceful shutdown signal)..."
48
+ echo "$INITIAL_PIDS" | while read pid; do
49
+ if kill -0 "$pid" 2>/dev/null; then
50
+ log " Sending SIGTERM to PID $pid"
51
+ kill -TERM "$pid" 2>/dev/null || log " Warning: Could not send SIGTERM to $pid"
52
+ fi
53
+ done
54
+
55
+ # Step 3: Wait for graceful shutdown with timeout
56
+ log ""
57
+ log "Step 3: Waiting up to $TIMEOUT_SECONDS seconds for graceful shutdown..."
58
+ elapsed=0
59
+ completed_pids=""
60
+ remaining_pids="$INITIAL_PIDS"
61
+
62
+ while [ $elapsed -lt $TIMEOUT_SECONDS ]; do
63
+ current_pids=$(get_boss_pids)
64
+
65
+ if [ -z "$current_pids" ]; then
66
+ log "✅ All processes terminated gracefully after $elapsed seconds"
67
+ echo ""
68
+ log "========================================"
69
+ log "SHUTDOWN COMPLETE - ALL PROCESSES EXITED GRACEFULLY"
70
+ log "========================================"
71
+ log "Total processes shutdown: $INITIAL_COUNT"
72
+ log "Graceful exits: $INITIAL_COUNT"
73
+ log "Forced kills: 0"
74
+ log "Time taken: ${elapsed}s / ${TIMEOUT_SECONDS}s"
75
+ log "Log file: $LOG_FILE"
76
+ exit 0
77
+ fi
78
+
79
+ # Calculate which processes have exited
80
+ new_completed=$(comm -23 <(echo "$remaining_pids" | sort) <(echo "$current_pids" | sort))
81
+ if [ -n "$new_completed" ]; then
82
+ echo "$new_completed" | while read pid; do
83
+ log " ✅ PID $pid exited gracefully"
84
+ done
85
+ completed_pids="$completed_pids$new_completed"$'\n'
86
+ remaining_pids="$current_pids"
87
+ fi
88
+
89
+ sleep $POLL_INTERVAL
90
+ elapsed=$((elapsed + POLL_INTERVAL))
91
+
92
+ # Progress update every 30 seconds
93
+ if [ $((elapsed % 30)) -eq 0 ]; then
94
+ remaining_count=$(echo "$current_pids" | wc -l | tr -d ' ')
95
+ log " Progress: ${elapsed}s elapsed, $remaining_count processes still running"
96
+ fi
97
+ done
98
+
99
+ # Step 4: Force kill remaining processes
100
+ log ""
101
+ log "Step 4: Timeout reached. Force killing remaining processes..."
102
+ REMAINING_PIDS=$(get_boss_pids)
103
+
104
+ if [ -z "$REMAINING_PIDS" ]; then
105
+ log "✅ All processes terminated during wait period"
106
+ echo ""
107
+ log "========================================"
108
+ log "SHUTDOWN COMPLETE - ALL PROCESSES EXITED"
109
+ log "========================================"
110
+ exit 0
111
+ fi
112
+
113
+ killed_count=0
114
+ echo "$REMAINING_PIDS" | while read pid; do
115
+ if kill -0 "$pid" 2>/dev/null; then
116
+ log " ⚠️ Sending SIGKILL to PID $pid"
117
+ kill -9 "$pid" 2>/dev/null || log " Warning: Could not kill $pid"
118
+ killed_count=$((killed_count + 1))
119
+ fi
120
+ done
121
+
122
+ # Wait a moment for kills to complete
123
+ sleep 2
124
+
125
+ # Final verification
126
+ FINAL_PIDS=$(get_boss_pids)
127
+ if [ -n "$FINAL_PIDS" ]; then
128
+ log ""
129
+ log "❌ WARNING: Some processes could not be terminated:"
130
+ echo "$FINAL_PIDS" | while read pid; do
131
+ log " PID $pid still running"
132
+ done
133
+ fi
134
+
135
+ # Summary
136
+ log ""
137
+ log "========================================"
138
+ log "SHUTDOWN COMPLETE"
139
+ log "========================================"
140
+
141
+ graceful_count=$(echo "$completed_pids" | grep -v '^$' | wc -l | tr -d ' ')
142
+ forced_count=$(echo "$REMAINING_PIDS" | wc -l | tr -d ' ')
143
+
144
+ log "Total processes found: $INITIAL_COUNT"
145
+ log "Graceful exits: $graceful_count"
146
+ log "Forced kills: $forced_count"
147
+ log "Time taken: ${elapsed}s / ${TIMEOUT_SECONDS}s"
148
+ log "Log file: $LOG_FILE"
149
+
150
+ if [ -z "$FINAL_PIDS" ]; then
151
+ log "✅ All processes successfully terminated"
152
+ exit 0
153
+ else
154
+ log "⚠️ Some processes could not be terminated"
155
+ exit 1
156
+ fi
@@ -0,0 +1,373 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * INSTALL ONYX HOOKS - Runtime Integration Script
4
+ *
5
+ * Installs pre-hook system into Claude Code for ONYX agent.
6
+ * This script patches tool execution to enforce delegation rules.
7
+ *
8
+ * USAGE:
9
+ * node scripts/install-onyx-hooks.js [--force]
10
+ * npm run install:onyx-hooks
11
+ */
12
+
13
+ import fs from 'fs/promises';
14
+ import path from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ import chalk from 'chalk';
17
+ import ora from 'ora';
18
+
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = path.dirname(__filename);
21
+ const projectRoot = path.dirname(__dirname);
22
+
23
+ // Hook installation targets
24
+ const HOOK_TARGETS = {
25
+ // Global Claude Code config (if exists)
26
+ claudeConfig: path.join(process.env.HOME, '.claude', 'config.json'),
27
+
28
+ // Project-level hook config
29
+ projectHook: path.join(projectRoot, '.claude-hooks', 'onyx-pre-hook.json'),
30
+
31
+ // NPM package bin
32
+ npmBin: path.join(projectRoot, 'bin', 'onyx-guard.js')
33
+ };
34
+
35
+ /**
36
+ * Install ONYX pre-hook configuration
37
+ */
38
+ async function installHooks(options = {}) {
39
+ console.log(chalk.blue('\n🔧 Installing ONYX Pre-Hook System\n'));
40
+
41
+ const spinner = ora('Checking environment...').start();
42
+
43
+ try {
44
+ // 1. Create hook directory
45
+ spinner.text = 'Creating hook directory...';
46
+ await createHookDirectory();
47
+ spinner.succeed('Hook directory created');
48
+
49
+ // 2. Install hook configuration
50
+ spinner.start('Installing hook configuration...');
51
+ await installHookConfig(options);
52
+ spinner.succeed('Hook configuration installed');
53
+
54
+ // 3. Make executables executable
55
+ spinner.start('Setting executable permissions...');
56
+ await setExecutablePermissions();
57
+ spinner.succeed('Executable permissions set');
58
+
59
+ // 4. Create symlinks (if needed)
60
+ spinner.start('Creating symlinks...');
61
+ await createSymlinks();
62
+ spinner.succeed('Symlinks created');
63
+
64
+ // 5. Verify installation
65
+ spinner.start('Verifying installation...');
66
+ const verified = await verifyInstallation();
67
+
68
+ if (verified) {
69
+ spinner.succeed('Installation verified');
70
+ } else {
71
+ spinner.warn('Installation verification failed - may need manual setup');
72
+ }
73
+
74
+ // Success summary
75
+ console.log(chalk.green('\n✅ ONYX Pre-Hook System Installed Successfully\n'));
76
+
77
+ printUsageInstructions();
78
+
79
+ } catch (error) {
80
+ spinner.fail('Installation failed');
81
+ console.error(chalk.red(`\nError: ${error.message}\n`));
82
+
83
+ if (error.stack && options.verbose) {
84
+ console.error(chalk.dim(error.stack));
85
+ }
86
+
87
+ process.exit(1);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Create .claude-hooks directory
93
+ */
94
+ async function createHookDirectory() {
95
+ const hookDir = path.dirname(HOOK_TARGETS.projectHook);
96
+
97
+ try {
98
+ await fs.mkdir(hookDir, { recursive: true });
99
+ } catch (error) {
100
+ if (error.code !== 'EEXIST') {
101
+ throw error;
102
+ }
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Install hook configuration file
108
+ */
109
+ async function installHookConfig(options) {
110
+ const hookConfig = {
111
+ name: 'ONYX Pre-Hook Tool Interceptor',
112
+ version: '1.0.0',
113
+ enabled: true,
114
+ agent: 'ONYX',
115
+ interceptor: {
116
+ module: '@cpretzinger/boss-claude/lib/onyx-tool-interceptor.js',
117
+ wrapper: '@cpretzinger/boss-claude/lib/onyx-wrapper.js',
118
+ cli: 'onyx-guard'
119
+ },
120
+ rules: {
121
+ forbiddenTools: [
122
+ 'Read',
123
+ 'Write',
124
+ 'Edit',
125
+ 'Bash',
126
+ 'Grep',
127
+ 'Glob',
128
+ 'NotebookEdit'
129
+ ],
130
+ allowedTools: [
131
+ 'Task',
132
+ 'WebFetch',
133
+ 'WebSearch',
134
+ 'TodoWrite',
135
+ 'Skill'
136
+ ],
137
+ delegationTarget: 'Task',
138
+ enforceStrict: true
139
+ },
140
+ logging: {
141
+ enabled: true,
142
+ violations: true,
143
+ delegations: true,
144
+ overrides: true
145
+ },
146
+ created: new Date().toISOString(),
147
+ installedBy: process.env.USER || 'unknown'
148
+ };
149
+
150
+ // Check if config already exists
151
+ try {
152
+ const existing = await fs.readFile(HOOK_TARGETS.projectHook, 'utf-8');
153
+ const existingConfig = JSON.parse(existing);
154
+
155
+ if (!options.force && existingConfig.enabled) {
156
+ console.log(chalk.yellow('\n⚠️ Hook configuration already exists'));
157
+ console.log(chalk.dim('Use --force to overwrite'));
158
+ return;
159
+ }
160
+ } catch (error) {
161
+ // File doesn't exist - continue with installation
162
+ }
163
+
164
+ // Write configuration
165
+ await fs.writeFile(
166
+ HOOK_TARGETS.projectHook,
167
+ JSON.stringify(hookConfig, null, 2),
168
+ 'utf-8'
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Set executable permissions on scripts
174
+ */
175
+ async function setExecutablePermissions() {
176
+ const executables = [
177
+ path.join(projectRoot, 'bin', 'onyx-guard.sh'),
178
+ path.join(projectRoot, 'bin', 'onyx-guard.js'),
179
+ path.join(projectRoot, 'lib', 'onyx-tool-interceptor.js'),
180
+ path.join(projectRoot, 'lib', 'onyx-wrapper.js')
181
+ ];
182
+
183
+ for (const exe of executables) {
184
+ try {
185
+ await fs.chmod(exe, 0o755);
186
+ } catch (error) {
187
+ if (error.code !== 'ENOENT') {
188
+ throw error;
189
+ }
190
+ }
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Create symlinks for easy access
196
+ */
197
+ async function createSymlinks() {
198
+ // Symlink onyx-guard to project node_modules/.bin
199
+ const binDir = path.join(projectRoot, 'node_modules', '.bin');
200
+
201
+ try {
202
+ await fs.mkdir(binDir, { recursive: true });
203
+
204
+ const symlinkTarget = path.join(binDir, 'onyx-guard');
205
+ const symlinkSource = path.join(projectRoot, 'bin', 'onyx-guard.js');
206
+
207
+ try {
208
+ await fs.symlink(symlinkSource, symlinkTarget);
209
+ } catch (error) {
210
+ if (error.code !== 'EEXIST') {
211
+ // Symlink already exists or can't be created - not critical
212
+ }
213
+ }
214
+ } catch (error) {
215
+ // Not critical if symlinks fail
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Verify installation
221
+ */
222
+ async function verifyInstallation() {
223
+ const checks = [];
224
+
225
+ // Check hook config exists
226
+ try {
227
+ await fs.access(HOOK_TARGETS.projectHook);
228
+ checks.push({ name: 'Hook config', status: true });
229
+ } catch (error) {
230
+ checks.push({ name: 'Hook config', status: false });
231
+ }
232
+
233
+ // Check interceptor module exists
234
+ try {
235
+ await fs.access(path.join(projectRoot, 'lib', 'onyx-tool-interceptor.js'));
236
+ checks.push({ name: 'Interceptor module', status: true });
237
+ } catch (error) {
238
+ checks.push({ name: 'Interceptor module', status: false });
239
+ }
240
+
241
+ // Check wrapper module exists
242
+ try {
243
+ await fs.access(path.join(projectRoot, 'lib', 'onyx-wrapper.js'));
244
+ checks.push({ name: 'Wrapper module', status: true });
245
+ } catch (error) {
246
+ checks.push({ name: 'Wrapper module', status: false });
247
+ }
248
+
249
+ // Check CLI exists
250
+ try {
251
+ await fs.access(path.join(projectRoot, 'bin', 'onyx-guard.js'));
252
+ checks.push({ name: 'CLI tool', status: true });
253
+ } catch (error) {
254
+ checks.push({ name: 'CLI tool', status: false });
255
+ }
256
+
257
+ const allPassed = checks.every(c => c.status);
258
+
259
+ if (!allPassed) {
260
+ console.log(chalk.yellow('\n⚠️ Verification Issues:'));
261
+ checks.forEach(check => {
262
+ const icon = check.status ? chalk.green('✓') : chalk.red('✗');
263
+ console.log(` ${icon} ${check.name}`);
264
+ });
265
+ }
266
+
267
+ return allPassed;
268
+ }
269
+
270
+ /**
271
+ * Print usage instructions
272
+ */
273
+ function printUsageInstructions() {
274
+ console.log(chalk.cyan('📚 USAGE INSTRUCTIONS:\n'));
275
+
276
+ console.log(chalk.white('1. Programmatic Integration:'));
277
+ console.log(chalk.dim(' import onyxWrapper from "@cpretzinger/boss-claude/lib/onyx-wrapper.js";'));
278
+ console.log(chalk.dim(' const result = await onyxWrapper.executeTool("Read", { file_path: "..." });'));
279
+ console.log();
280
+
281
+ console.log(chalk.white('2. CLI Usage:'));
282
+ console.log(chalk.dim(' npx onyx-guard check Read'));
283
+ console.log(chalk.dim(' npx onyx-guard intercept Bash --params \'{"command":"npm install"}\''));
284
+ console.log(chalk.dim(' npx onyx-guard report'));
285
+ console.log();
286
+
287
+ console.log(chalk.white('3. Shell Script:'));
288
+ console.log(chalk.dim(' ./bin/onyx-guard.sh --tool Read --file /path/to/file.js'));
289
+ console.log(chalk.dim(' ./bin/onyx-guard.sh --list-forbidden'));
290
+ console.log();
291
+
292
+ console.log(chalk.white('4. Configuration:'));
293
+ console.log(chalk.dim(` Edit: ${HOOK_TARGETS.projectHook}`));
294
+ console.log();
295
+
296
+ console.log(chalk.green('✅ Pre-hooks are now active for ONYX agent\n'));
297
+ }
298
+
299
+ /**
300
+ * Uninstall hooks
301
+ */
302
+ async function uninstallHooks() {
303
+ console.log(chalk.yellow('\n🗑️ Uninstalling ONYX Pre-Hook System\n'));
304
+
305
+ const spinner = ora('Removing hook configuration...').start();
306
+
307
+ try {
308
+ // Remove hook config
309
+ try {
310
+ await fs.unlink(HOOK_TARGETS.projectHook);
311
+ spinner.succeed('Hook configuration removed');
312
+ } catch (error) {
313
+ if (error.code !== 'ENOENT') {
314
+ throw error;
315
+ }
316
+ spinner.warn('Hook configuration not found');
317
+ }
318
+
319
+ // Remove hook directory if empty
320
+ try {
321
+ const hookDir = path.dirname(HOOK_TARGETS.projectHook);
322
+ await fs.rmdir(hookDir);
323
+ } catch (error) {
324
+ // Directory not empty or doesn't exist - ignore
325
+ }
326
+
327
+ console.log(chalk.green('\n✅ ONYX Pre-Hook System Uninstalled\n'));
328
+
329
+ } catch (error) {
330
+ spinner.fail('Uninstallation failed');
331
+ console.error(chalk.red(`\nError: ${error.message}\n`));
332
+ process.exit(1);
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Main CLI
338
+ */
339
+ async function main() {
340
+ const args = process.argv.slice(2);
341
+ const command = args[0];
342
+
343
+ const options = {
344
+ force: args.includes('--force'),
345
+ verbose: args.includes('--verbose')
346
+ };
347
+
348
+ switch (command) {
349
+ case 'uninstall':
350
+ case 'remove':
351
+ await uninstallHooks();
352
+ break;
353
+
354
+ case 'verify':
355
+ await verifyInstallation();
356
+ break;
357
+
358
+ case 'install':
359
+ default:
360
+ await installHooks(options);
361
+ break;
362
+ }
363
+ }
364
+
365
+ // Run if executed directly
366
+ if (import.meta.url === `file://${process.argv[1]}`) {
367
+ main().catch(error => {
368
+ console.error(chalk.red('Fatal error:'), error);
369
+ process.exit(1);
370
+ });
371
+ }
372
+
373
+ export { installHooks, uninstallHooks, verifyInstallation };
@@ -6,6 +6,7 @@ import fs from 'fs';
6
6
  import os from 'os';
7
7
  import { execSync } from 'child_process';
8
8
  import chalk from 'chalk';
9
+ import { importCredentials } from '../lib/setup/import-credentials.js';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = dirname(__filename);
@@ -21,23 +22,17 @@ try {
21
22
  console.log(chalk.green('✅ Created ~/.boss-claude directory'));
22
23
  }
23
24
 
24
- // Copy .env.example to ~/.boss-claude/.env if it doesn't exist
25
+ // Use credential import system instead of copying template
25
26
  const envDestPath = join(bossDirPath, '.env');
26
27
 
27
28
  if (!fs.existsSync(envDestPath)) {
28
- const envSourcePath = join(__dirname, '..', 'config', '.env.example');
29
-
30
- if (fs.existsSync(envSourcePath)) {
31
- fs.copyFileSync(envSourcePath, envDestPath);
32
- console.log(chalk.green('✅ Created ~/.boss-claude/.env from template'));
33
- console.log(chalk.yellow('\n⚠️ IMPORTANT: Edit ~/.boss-claude/.env with your credentials:'));
34
- console.log(chalk.gray(' - REDIS_URL (required)'));
35
- console.log(chalk.gray(' - GITHUB_TOKEN (required)'));
36
- console.log(chalk.gray(' - GITHUB_OWNER (optional)'));
37
- console.log(chalk.gray(' - GITHUB_MEMORY_REPO (optional)\n'));
38
- }
29
+ console.log(chalk.blue('\n🔐 Setting up credentials...\n'));
30
+
31
+ // Auto-detect and import credentials
32
+ await importCredentials();
39
33
  } else {
40
- console.log(chalk.blue('ℹ️ ~/.boss-claude/.env already exists (skipping)'));
34
+ console.log(chalk.blue('ℹ️ ~/.boss-claude/.env already exists (skipping credential import)'));
35
+ console.log(chalk.gray(' Run "boss-claude setup" to re-import credentials'));
41
36
  }
42
37
 
43
38
  // Update ~/.claude/CLAUDE.md to auto-load Boss
@@ -45,11 +40,117 @@ try {
45
40
  const claudeMdPath = join(claudeDirPath, 'CLAUDE.md');
46
41
 
47
42
  const bossAutoLoadBlock = `
48
- # BOSS CLAUDE AUTO-LOAD
49
- \`\`\`javascript
50
- import { formatStatusForClaude } from '@cpretzinger/boss-claude/lib/init.js';
51
- console.log(await formatStatusForClaude());
43
+ # ONYX MODE - Boss Claude
44
+
45
+ You are **ONYX**, THE CONDUCTOR. I direct, I don't play.
46
+
47
+ ## 🏆 THE WIN CONDITION
48
+
49
+ **I WIN BY SHIPPING.** A project is WON when it is:
50
+ - ✅ COMPLETE - All features implemented
51
+ - ✅ WORKING - Passes all tests, no crashes
52
+ - ✅ BUG-FREE - No known issues
53
+ - ✅ SELLABLE - Production-ready, documented
54
+ - ✅ SCALABLE - Handles growth, maintainable
55
+
56
+ > "I don't get XP for talking. I get XP for shipping."
57
+
58
+ ## 🎼 THE CONDUCTOR'S RULE
59
+
60
+ > "The conductor never plays an instrument. I wave the baton. My musicians make the music."
61
+
62
+ ## 🚨 MANDATORY: Session Start
63
+
64
+ **ALWAYS run these FIRST before any work:**
65
+ \`\`\`bash
66
+ boss-claude status
67
+ boss-claude recall "recent work"
68
+ \`\`\`
69
+
70
+ ## ⛔ FORBIDDEN TOOLS (Never Touch These)
71
+
72
+ ❌ Read, Write, Edit, Bash, Grep, Glob, NotebookEdit
73
+
74
+ These are for MUSICIANS (agents), not the CONDUCTOR (me).
75
+
76
+ ## ✅ ALLOWED TOOLS (My Baton)
77
+
78
+ ✅ Task (spawn agents - PRIMARY), TodoWrite, WebSearch, WebFetch, Skill, AskUserQuestion
79
+
80
+ ## 🚀 MAX SPEED: PARALLEL AGENTS
81
+
82
+ **Always spawn independent tasks IN PARALLEL (same message, multiple Task calls).**
83
+
84
+ ❌ Slow: Task 1 → wait → Task 2 → wait → Task 3
85
+ ✅ Fast: Task 1 + Task 2 + Task 3 (all at once)
86
+
87
+ ## 🏛️ HIERARCHY (Complex Tasks)
88
+
89
+ ONYX → Domain Boss → Workers → Review → Report
90
+ Use hierarchy when domain expertise matters (auth, db, api).
91
+
92
+ ## 🎯 DELEGATION MATRIX
93
+
94
+ | User Says | I Spawn | With Prompt |
95
+ |-----------|---------|-------------|
96
+ | "find/search/where is" | Task(Explore) | "Search codebase for..." |
97
+ | "read/show/what's in" | Task(Explore) | "Read and summarize..." |
98
+ | "build/create/implement" | Task(general-purpose) | "Implement..." |
99
+ | "fix/debug/error" | Task(general-purpose) | "Debug and fix..." |
100
+ | "run/execute/npm/git" | Task(Bash) | "Execute command..." |
101
+ | "test/verify" | Task(Bash) | "Run tests..." |
102
+ | "plan/design/architect" | Task(Plan) | "Design approach for..." |
103
+ | Multiple files | PARALLEL Task() | Spawn all at once! |
104
+
105
+ ## ⚡ XP EFFICIENCY FORMULA
106
+
107
+ \`\`\`
108
+ Base XP: 50
109
+ Efficiency: + min(100, floor(agent_tokens / onyx_tokens))
110
+ Delegations: + min(20, delegations * 2)
111
+ ────────────────────────────────────────
112
+ Max XP/session: 170
52
113
  \`\`\`
114
+
115
+ **Goal**: Keep ONYX tokens < 5% of total. Let agents do 95%+ of work.
116
+
117
+ | Efficiency Ratio | Bonus XP | Rating |
118
+ |------------------|----------|--------|
119
+ | 50x+ | +50 | 🏆 Perfect Conductor |
120
+ | 20x-49x | +20-49 | ✅ Good Conductor |
121
+ | 5x-19x | +5-19 | ⚠️ Could Delegate More |
122
+ | <5x | +0-4 | ❌ Playing, Not Conducting |
123
+
124
+ ## 🔄 THE SHIPPING LOOP
125
+
126
+ 1. **UNDERSTAND** - What does user want? → TodoWrite
127
+ 2. **DECOMPOSE** - Break into subtasks
128
+ 3. **DELEGATE** - Spawn parallel agents via Task
129
+ 4. **SYNTHESIZE** - Review agent outputs
130
+ 5. **VERIFY** - Task(Bash): "Run tests"
131
+ 6. **REPORT** - Tell user what shipped
132
+
133
+ ## 🛑 STUCK WORKER PROTOCOL
134
+
135
+ If agent takes >60s (simple) or >300s (complex):
136
+ \`\`\`bash
137
+ boss-claude agent:kill <id> # Kill specific agent
138
+ boss-claude agent:kill-all # Nuclear option
139
+ \`\`\`
140
+
141
+ ## ⏱️ CONTEXT REFRESH
142
+
143
+ Run \`boss-claude status\` every 30 seconds to see efficiency tracker.
144
+
145
+ ## Commands
146
+ \`\`\`bash
147
+ boss-claude status # ALWAYS RUN FIRST - shows efficiency
148
+ boss-claude recall # Load memory
149
+ boss-claude save # Save session (earn XP!)
150
+ boss-claude watch # Monitor agents in real-time
151
+ \`\`\`
152
+
153
+ ---
53
154
  `;
54
155
 
55
156
  if (!fs.existsSync(claudeDirPath)) {
@@ -59,7 +160,7 @@ console.log(await formatStatusForClaude());
59
160
  if (fs.existsSync(claudeMdPath)) {
60
161
  const content = fs.readFileSync(claudeMdPath, 'utf8');
61
162
 
62
- if (!content.includes('BOSS CLAUDE AUTO-LOAD')) {
163
+ if (!content.includes('ONYX MODE - Boss Claude')) {
63
164
  fs.appendFileSync(claudeMdPath, bossAutoLoadBlock);
64
165
  console.log(chalk.green('✅ Added Boss Claude auto-load to ~/.claude/CLAUDE.md'));
65
166
  } else {