@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,251 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # ONYX GUARD - Pre-Hook Tool Interceptor
4
+ #
5
+ # Executable shell script that wraps ONYX agent execution
6
+ # and enforces delegation rules via JavaScript interceptor.
7
+ #
8
+ # USAGE:
9
+ # ./onyx-guard.sh --tool Read --file /path/to/file.js
10
+ # ./onyx-guard.sh --tool Bash --command "npm install"
11
+ # ./onyx-guard.sh --check-tool Read
12
+ #
13
+
14
+ set -euo pipefail
15
+
16
+ # Colors for terminal output
17
+ RED='\033[0;31m'
18
+ GREEN='\033[0;32m'
19
+ YELLOW='\033[1;33m'
20
+ BLUE='\033[0;34m'
21
+ CYAN='\033[0;36m'
22
+ DIM='\033[2m'
23
+ RESET='\033[0m'
24
+
25
+ # Script directory
26
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
27
+ LIB_DIR="$(dirname "$SCRIPT_DIR")/lib"
28
+
29
+ # FORBIDDEN TOOLS for ONYX
30
+ FORBIDDEN_TOOLS=("Read" "Write" "Edit" "Bash" "Grep" "Glob" "NotebookEdit")
31
+
32
+ # ALLOWED TOOLS for ONYX
33
+ ALLOWED_TOOLS=("Task" "WebFetch" "WebSearch" "TodoWrite" "Skill")
34
+
35
+ # Check if tool is forbidden
36
+ is_forbidden_tool() {
37
+ local tool="$1"
38
+ for forbidden in "${FORBIDDEN_TOOLS[@]}"; do
39
+ if [[ "$tool" == "$forbidden" ]]; then
40
+ return 0
41
+ fi
42
+ done
43
+ return 1
44
+ }
45
+
46
+ # Check if tool is allowed
47
+ is_allowed_tool() {
48
+ local tool="$1"
49
+ for allowed in "${ALLOWED_TOOLS[@]}"; do
50
+ if [[ "$tool" == "$allowed" ]]; then
51
+ return 0
52
+ fi
53
+ done
54
+ return 1
55
+ }
56
+
57
+ # Block forbidden tool and suggest delegation
58
+ block_tool() {
59
+ local tool="$1"
60
+ shift
61
+ local params="$*"
62
+
63
+ echo -e "${RED}"
64
+ echo "═══════════════════════════════════════════════════════════════════════════════"
65
+ echo "🚨 ONYX TOOL BLOCK TRIGGERED"
66
+ echo "═══════════════════════════════════════════════════════════════════════════════"
67
+ echo -e "${RESET}"
68
+
69
+ echo -e "${YELLOW}Agent:${RESET} ONYX"
70
+ echo -e "${YELLOW}Forbidden Tool:${RESET} ${RED}${tool}${RESET}"
71
+ echo -e "${YELLOW}Params:${RESET} ${DIM}${params}${RESET}"
72
+
73
+ echo ""
74
+ echo -e "${YELLOW}📋 ONYX DELEGATION RULE:${RESET}"
75
+ echo -e "${DIM} ONYX is META-BOSS and NEVER touches files directly${RESET}"
76
+ echo -e "${DIM} ONYX delegates to Task tool → Task tool uses file operations${RESET}"
77
+ echo -e "${RED} FORBIDDEN: ONYX → ${tool} (direct file access)${RESET}"
78
+ echo -e "${GREEN} ALLOWED: ONYX → Task → ${tool} (delegated access)${RESET}"
79
+
80
+ echo ""
81
+ echo -e "${CYAN}✅ DELEGATION MESSAGE:${RESET}"
82
+
83
+ case "$tool" in
84
+ Read)
85
+ echo -e "${GREEN}Use Task tool: \"Read the file at ${params}\"${RESET}"
86
+ ;;
87
+ Write)
88
+ echo -e "${GREEN}Use Task tool: \"Write content to ${params}\"${RESET}"
89
+ ;;
90
+ Edit)
91
+ echo -e "${GREEN}Use Task tool: \"Edit the file ${params}\"${RESET}"
92
+ ;;
93
+ Bash)
94
+ echo -e "${GREEN}Use Task tool: \"Execute bash command: ${params}\"${RESET}"
95
+ ;;
96
+ Grep)
97
+ echo -e "${GREEN}Use Task tool: \"Search for pattern ${params}\"${RESET}"
98
+ ;;
99
+ Glob)
100
+ echo -e "${GREEN}Use Task tool: \"Find files matching pattern ${params}\"${RESET}"
101
+ ;;
102
+ *)
103
+ echo -e "${GREEN}Use Task tool: \"Execute ${tool} with params ${params}\"${RESET}"
104
+ ;;
105
+ esac
106
+
107
+ echo ""
108
+ echo -e "${RED}❌ TOOL CALL BLOCKED${RESET}"
109
+ echo -e "${YELLOW}⚠️ ONYX must delegate to Task tool instead${RESET}"
110
+ echo ""
111
+
112
+ exit 1
113
+ }
114
+
115
+ # Allow tool with confirmation
116
+ allow_tool() {
117
+ local tool="$1"
118
+ echo -e "${GREEN}✅ Tool ${tool} is allowed for ONYX${RESET}"
119
+ exit 0
120
+ }
121
+
122
+ # Main guard logic
123
+ guard_tool() {
124
+ local tool="$1"
125
+ shift
126
+ local params="$*"
127
+
128
+ # Check if forbidden
129
+ if is_forbidden_tool "$tool"; then
130
+ block_tool "$tool" "$params"
131
+ fi
132
+
133
+ # Check if allowed
134
+ if is_allowed_tool "$tool"; then
135
+ allow_tool "$tool"
136
+ fi
137
+
138
+ # Unknown tool - warn but allow
139
+ echo -e "${YELLOW}⚠️ Unknown tool for ONYX: ${tool}${RESET}"
140
+ echo -e "${DIM}Allowing by default - add to ALLOWED_TOOLS or FORBIDDEN_TOOLS${RESET}"
141
+ exit 0
142
+ }
143
+
144
+ # Check tool status without blocking
145
+ check_tool() {
146
+ local tool="$1"
147
+
148
+ if is_forbidden_tool "$tool"; then
149
+ echo -e "${RED}FORBIDDEN${RESET}: ${tool} (ONYX must delegate to Task)"
150
+ exit 1
151
+ elif is_allowed_tool "$tool"; then
152
+ echo -e "${GREEN}ALLOWED${RESET}: ${tool}"
153
+ exit 0
154
+ else
155
+ echo -e "${YELLOW}UNKNOWN${RESET}: ${tool}"
156
+ exit 2
157
+ fi
158
+ }
159
+
160
+ # Run JavaScript interceptor
161
+ run_js_interceptor() {
162
+ if [[ -f "$LIB_DIR/onyx-tool-interceptor.js" ]]; then
163
+ node -e "
164
+ import('$LIB_DIR/onyx-tool-interceptor.js').then(module => {
165
+ const interceptor = module.default;
166
+ interceptor.printReport();
167
+ });
168
+ "
169
+ else
170
+ echo -e "${YELLOW}⚠️ JavaScript interceptor not found${RESET}"
171
+ fi
172
+ }
173
+
174
+ # Print help
175
+ print_help() {
176
+ cat << EOF
177
+ ${CYAN}ONYX GUARD - Tool Interceptor for ONYX Agent${RESET}
178
+
179
+ USAGE:
180
+ onyx-guard.sh --tool <TOOL_NAME> [PARAMS...]
181
+ onyx-guard.sh --check-tool <TOOL_NAME>
182
+ onyx-guard.sh --list-forbidden
183
+ onyx-guard.sh --list-allowed
184
+ onyx-guard.sh --report
185
+
186
+ OPTIONS:
187
+ --tool <NAME> Guard a tool call (blocks forbidden tools)
188
+ --check-tool <NAME> Check if tool is allowed (no blocking)
189
+ --list-forbidden List all forbidden tools for ONYX
190
+ --list-allowed List all allowed tools for ONYX
191
+ --report Show JavaScript interceptor report
192
+ -h, --help Show this help message
193
+
194
+ EXAMPLES:
195
+ # Block Read tool (forbidden for ONYX)
196
+ onyx-guard.sh --tool Read --file /path/to/file.js
197
+
198
+ # Allow Task tool (allowed for ONYX)
199
+ onyx-guard.sh --tool Task --description "Search for files"
200
+
201
+ # Check if tool is allowed
202
+ onyx-guard.sh --check-tool Bash
203
+
204
+ FORBIDDEN TOOLS (ONYX must delegate):
205
+ Read, Write, Edit, Bash, Grep, Glob, NotebookEdit
206
+
207
+ ALLOWED TOOLS (ONYX can use directly):
208
+ Task, WebFetch, WebSearch, TodoWrite, Skill
209
+
210
+ DELEGATION RULE:
211
+ ONYX is META-BOSS and NEVER touches files directly.
212
+ ONYX delegates to Task tool → Task tool uses file operations.
213
+
214
+ EOF
215
+ }
216
+
217
+ # Parse command line arguments
218
+ case "${1:-}" in
219
+ --tool)
220
+ shift
221
+ guard_tool "$@"
222
+ ;;
223
+ --check-tool)
224
+ shift
225
+ check_tool "$1"
226
+ ;;
227
+ --list-forbidden)
228
+ echo -e "${RED}FORBIDDEN TOOLS FOR ONYX:${RESET}"
229
+ for tool in "${FORBIDDEN_TOOLS[@]}"; do
230
+ echo -e " ${RED}✗${RESET} $tool"
231
+ done
232
+ ;;
233
+ --list-allowed)
234
+ echo -e "${GREEN}ALLOWED TOOLS FOR ONYX:${RESET}"
235
+ for tool in "${ALLOWED_TOOLS[@]}"; do
236
+ echo -e " ${GREEN}✓${RESET} $tool"
237
+ done
238
+ ;;
239
+ --report)
240
+ run_js_interceptor
241
+ ;;
242
+ -h|--help)
243
+ print_help
244
+ ;;
245
+ *)
246
+ echo -e "${RED}Error: Invalid arguments${RESET}"
247
+ echo ""
248
+ print_help
249
+ exit 1
250
+ ;;
251
+ esac
package/bin/prompts.js ADDED
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Interactive Prompts for Boss Claude Setup Wizard
3
+ * Beautiful CLI prompts using readline and chalk
4
+ */
5
+
6
+ import readline from 'readline';
7
+ import chalk from 'chalk';
8
+
9
+ /**
10
+ * Create readline interface
11
+ */
12
+ function createInterface() {
13
+ return readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Ask a question and get user input
21
+ */
22
+ export function ask(question, defaultValue = '') {
23
+ return new Promise((resolve) => {
24
+ const rl = createInterface();
25
+
26
+ const prompt = defaultValue
27
+ ? `${question} ${chalk.dim(`(${defaultValue})`)}: `
28
+ : `${question}: `;
29
+
30
+ rl.question(prompt, (answer) => {
31
+ rl.close();
32
+ resolve(answer.trim() || defaultValue);
33
+ });
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Ask a yes/no question
39
+ */
40
+ export function confirm(question, defaultYes = true) {
41
+ return new Promise((resolve) => {
42
+ const rl = createInterface();
43
+
44
+ const hint = defaultYes ? chalk.dim('(Y/n)') : chalk.dim('(y/N)');
45
+ const prompt = `${question} ${hint}: `;
46
+
47
+ rl.question(prompt, (answer) => {
48
+ rl.close();
49
+
50
+ const normalized = answer.trim().toLowerCase();
51
+
52
+ if (!normalized) {
53
+ resolve(defaultYes);
54
+ return;
55
+ }
56
+
57
+ resolve(normalized === 'y' || normalized === 'yes');
58
+ });
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Ask for password/secret (hidden input)
64
+ */
65
+ export function askSecret(question) {
66
+ return new Promise((resolve) => {
67
+ const rl = createInterface();
68
+
69
+ // Disable echo for password input
70
+ const stdin = process.stdin;
71
+ const setRawMode = stdin.setRawMode;
72
+
73
+ let input = '';
74
+
75
+ rl.question(`${question}: `, () => {
76
+ // This won't be called due to raw mode
77
+ });
78
+
79
+ if (setRawMode) {
80
+ stdin.setRawMode(true);
81
+ }
82
+
83
+ stdin.on('data', (char) => {
84
+ const str = char.toString('utf-8');
85
+
86
+ // Handle Enter key
87
+ if (str === '\n' || str === '\r' || str === '\r\n') {
88
+ stdin.removeAllListeners('data');
89
+ if (setRawMode) {
90
+ stdin.setRawMode(false);
91
+ }
92
+ rl.close();
93
+ process.stdout.write('\n');
94
+ resolve(input);
95
+ return;
96
+ }
97
+
98
+ // Handle Ctrl+C
99
+ if (str === '\u0003') {
100
+ process.exit();
101
+ }
102
+
103
+ // Handle backspace
104
+ if (str === '\u007f' || str === '\b') {
105
+ if (input.length > 0) {
106
+ input = input.slice(0, -1);
107
+ process.stdout.write('\b \b');
108
+ }
109
+ return;
110
+ }
111
+
112
+ // Add character to input and show asterisk
113
+ input += str;
114
+ process.stdout.write('*');
115
+ });
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Show a spinner while executing async operation
121
+ */
122
+ export async function spinner(message, asyncFn) {
123
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
124
+ let i = 0;
125
+
126
+ process.stdout.write(`${message} ${frames[0]}`);
127
+
128
+ const intervalId = setInterval(() => {
129
+ i = (i + 1) % frames.length;
130
+ process.stdout.write(`\r${message} ${chalk.cyan(frames[i])}`);
131
+ }, 80);
132
+
133
+ try {
134
+ const result = await asyncFn();
135
+ clearInterval(intervalId);
136
+ process.stdout.write(`\r${message} ${chalk.green('✓')}\n`);
137
+ return { success: true, result };
138
+ } catch (error) {
139
+ clearInterval(intervalId);
140
+ process.stdout.write(`\r${message} ${chalk.red('✗')}\n`);
141
+ return { success: false, error };
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Display a section header
147
+ */
148
+ export function header(title, description = '') {
149
+ console.log('\n' + chalk.bold.blue('━'.repeat(60)));
150
+ console.log(chalk.bold.white(title));
151
+ if (description) {
152
+ console.log(chalk.dim(description));
153
+ }
154
+ console.log(chalk.bold.blue('━'.repeat(60)) + '\n');
155
+ }
156
+
157
+ /**
158
+ * Display a success message
159
+ */
160
+ export function success(message) {
161
+ console.log(chalk.green('✓') + ' ' + message);
162
+ }
163
+
164
+ /**
165
+ * Display an error message
166
+ */
167
+ export function error(message, details = '') {
168
+ console.log(chalk.red('✗') + ' ' + message);
169
+ if (details) {
170
+ console.log(chalk.dim(' ' + details));
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Display a warning message
176
+ */
177
+ export function warning(message) {
178
+ console.log(chalk.yellow('⚠') + ' ' + message);
179
+ }
180
+
181
+ /**
182
+ * Display an info message
183
+ */
184
+ export function info(message) {
185
+ console.log(chalk.blue('ℹ') + ' ' + message);
186
+ }
187
+
188
+ /**
189
+ * Display a list of items
190
+ */
191
+ export function list(items, style = 'bullet') {
192
+ items.forEach((item, idx) => {
193
+ const prefix = style === 'numbered'
194
+ ? chalk.dim(`${idx + 1}.`)
195
+ : chalk.dim('•');
196
+ console.log(` ${prefix} ${item}`);
197
+ });
198
+ }
199
+
200
+ /**
201
+ * Display a progress bar
202
+ */
203
+ export function progress(current, total, label = '') {
204
+ const percentage = Math.round((current / total) * 100);
205
+ const filled = Math.round((current / total) * 30);
206
+ const empty = 30 - filled;
207
+
208
+ const bar = chalk.green('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));
209
+ const text = label ? `${label} ` : '';
210
+
211
+ process.stdout.write(`\r${text}[${bar}] ${percentage}%`);
212
+
213
+ if (current === total) {
214
+ process.stdout.write('\n');
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Clear the screen
220
+ */
221
+ export function clear() {
222
+ process.stdout.write('\x1Bc');
223
+ }
224
+
225
+ /**
226
+ * Display a box with content
227
+ */
228
+ export function box(content, title = '') {
229
+ const lines = content.split('\n');
230
+ const maxLength = Math.max(...lines.map(l => l.length), title.length);
231
+ const width = Math.min(maxLength + 4, 60);
232
+
233
+ console.log('\n' + chalk.dim('┌' + '─'.repeat(width - 2) + '┐'));
234
+
235
+ if (title) {
236
+ const padding = Math.floor((width - title.length - 4) / 2);
237
+ console.log(chalk.dim('│') + ' '.repeat(padding) + chalk.bold(title) + ' '.repeat(width - padding - title.length - 3) + chalk.dim('│'));
238
+ console.log(chalk.dim('├' + '─'.repeat(width - 2) + '┤'));
239
+ }
240
+
241
+ lines.forEach(line => {
242
+ const paddedLine = line + ' '.repeat(width - line.length - 3);
243
+ console.log(chalk.dim('│') + ' ' + paddedLine + chalk.dim('│'));
244
+ });
245
+
246
+ console.log(chalk.dim('└' + '─'.repeat(width - 2) + '┘') + '\n');
247
+ }
248
+
249
+ /**
250
+ * Choose from a list of options
251
+ */
252
+ export async function choose(question, options) {
253
+ console.log(chalk.bold(question) + '\n');
254
+
255
+ options.forEach((option, idx) => {
256
+ console.log(chalk.dim(` ${idx + 1}.`) + ` ${option}`);
257
+ });
258
+
259
+ console.log();
260
+
261
+ while (true) {
262
+ const answer = await ask('Enter your choice (1-' + options.length + ')');
263
+ const choice = parseInt(answer);
264
+
265
+ if (choice >= 1 && choice <= options.length) {
266
+ return { index: choice - 1, value: options[choice - 1] };
267
+ }
268
+
269
+ error('Invalid choice. Please try again.');
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Pause and wait for user to press Enter
275
+ */
276
+ export function pause(message = 'Press Enter to continue...') {
277
+ return new Promise((resolve) => {
278
+ const rl = createInterface();
279
+ rl.question(chalk.dim(message), () => {
280
+ rl.close();
281
+ resolve();
282
+ });
283
+ });
284
+ }
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * BOSS CLAUDE - Rollback CLI
4
+ * Undo setup changes safely
5
+ */
6
+
7
+ import { RollbackManager } from '../lib/setup/rollback.js';
8
+ import chalk from 'chalk';
9
+
10
+ const args = process.argv.slice(2);
11
+
12
+ // Parse command line arguments
13
+ const options = {
14
+ verbose: args.includes('--verbose') || args.includes('-v'),
15
+ dryRun: args.includes('--dry-run') || args.includes('-d'),
16
+ force: args.includes('--force') || args.includes('-f'),
17
+ confirm: args.includes('--confirm') || args.includes('-y'),
18
+ help: args.includes('--help') || args.includes('-h')
19
+ };
20
+
21
+ // Show help
22
+ if (options.help || args.includes('help')) {
23
+ console.log(chalk.bold.cyan('\n🔄 BOSS CLAUDE ROLLBACK\n'));
24
+ console.log(chalk.white('Safely undo setup changes\n'));
25
+ console.log(chalk.bold('Usage:\n'));
26
+ console.log(chalk.white(' boss-claude rollback [options]\n'));
27
+ console.log(chalk.bold('Options:\n'));
28
+ console.log(chalk.white(' --confirm, -y Confirm rollback without prompts'));
29
+ console.log(chalk.white(' --dry-run, -d Show what would be rolled back (no changes)'));
30
+ console.log(chalk.white(' --force, -f Force rollback even if setup completed'));
31
+ console.log(chalk.white(' --verbose, -v Show detailed progress'));
32
+ console.log(chalk.white(' --help, -h Show this help message\n'));
33
+ console.log(chalk.bold('Examples:\n'));
34
+ console.log(chalk.gray(' # Preview rollback'));
35
+ console.log(chalk.cyan(' boss-claude rollback --dry-run\n'));
36
+ console.log(chalk.gray(' # Execute rollback'));
37
+ console.log(chalk.cyan(' boss-claude rollback --confirm\n'));
38
+ console.log(chalk.gray(' # Force rollback with verbose output'));
39
+ console.log(chalk.cyan(' boss-claude rollback --force --verbose\n'));
40
+ process.exit(0);
41
+ }
42
+
43
+ // Execute rollback
44
+ async function main() {
45
+ const manager = new RollbackManager(options);
46
+
47
+ if (!options.confirm && !options.dryRun) {
48
+ // Interactive mode
49
+ const result = await manager.rollbackInteractive();
50
+
51
+ if (result.requiresConfirmation) {
52
+ console.log(chalk.yellow('Add --confirm to execute rollback\n'));
53
+ process.exit(0);
54
+ }
55
+
56
+ if (result.success) {
57
+ process.exit(0);
58
+ } else {
59
+ process.exit(1);
60
+ }
61
+ }
62
+
63
+ // Execute rollback
64
+ const result = await manager.rollback();
65
+
66
+ if (result.success) {
67
+ console.log(chalk.green.bold('✓ Rollback completed successfully\n'));
68
+ process.exit(0);
69
+ } else {
70
+ console.log(chalk.red.bold('✗ Rollback failed\n'));
71
+ if (result.error) {
72
+ console.log(chalk.red(result.error + '\n'));
73
+ }
74
+ process.exit(1);
75
+ }
76
+ }
77
+
78
+ main().catch(error => {
79
+ console.error(chalk.red.bold('\n✗ Rollback error\n'));
80
+ console.error(chalk.red(error.message));
81
+ if (options.verbose && error.stack) {
82
+ console.error(chalk.gray('\n' + error.stack));
83
+ }
84
+ process.exit(1);
85
+ });