@automagik/genie 0.260202.530 → 0.260202.1833

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 (39) hide show
  1. package/dist/claudio.js +44 -45
  2. package/dist/genie.js +58 -135
  3. package/dist/term.js +134 -67
  4. package/install.sh +43 -7
  5. package/package.json +1 -1
  6. package/src/claudio.ts +31 -21
  7. package/src/commands/launch.ts +12 -68
  8. package/src/genie-commands/doctor.ts +327 -0
  9. package/src/genie-commands/setup.ts +317 -199
  10. package/src/genie-commands/uninstall.ts +176 -0
  11. package/src/genie.ts +24 -44
  12. package/src/lib/claude-settings.ts +22 -64
  13. package/src/lib/genie-config.ts +169 -57
  14. package/src/lib/orchestrator/completion.ts +392 -0
  15. package/src/lib/orchestrator/event-monitor.ts +442 -0
  16. package/src/lib/orchestrator/index.ts +12 -0
  17. package/src/lib/orchestrator/patterns.ts +277 -0
  18. package/src/lib/orchestrator/state-detector.ts +339 -0
  19. package/src/lib/version.ts +1 -1
  20. package/src/lib/worker-registry.ts +229 -0
  21. package/src/term-commands/close.ts +221 -0
  22. package/src/term-commands/exec.ts +28 -6
  23. package/src/term-commands/kill.ts +143 -0
  24. package/src/term-commands/orchestrate.ts +844 -0
  25. package/src/term-commands/read.ts +6 -1
  26. package/src/term-commands/shortcuts.ts +14 -14
  27. package/src/term-commands/work.ts +415 -0
  28. package/src/term-commands/workers.ts +264 -0
  29. package/src/term.ts +201 -3
  30. package/src/types/genie-config.ts +49 -81
  31. package/src/genie-commands/hooks.ts +0 -317
  32. package/src/lib/hook-script.ts +0 -263
  33. package/src/lib/hooks/compose.ts +0 -72
  34. package/src/lib/hooks/index.ts +0 -163
  35. package/src/lib/hooks/presets/audited.ts +0 -191
  36. package/src/lib/hooks/presets/collaborative.ts +0 -143
  37. package/src/lib/hooks/presets/sandboxed.ts +0 -153
  38. package/src/lib/hooks/presets/supervised.ts +0 -66
  39. package/src/lib/hooks/utils/escape.ts +0 -46
@@ -1,282 +1,400 @@
1
1
  /**
2
2
  * Genie Setup Command
3
3
  *
4
- * Interactive wizard for configuring genie hooks and settings.
5
- * Teaches users about hooks and lets them choose which to enable.
4
+ * Interactive wizard for configuring genie settings.
5
+ * Supports full wizard, quick mode, and section-specific setup.
6
6
  */
7
7
 
8
- import { checkbox, confirm, input } from '@inquirer/prompts';
8
+ import { confirm, input, select } from '@inquirer/prompts';
9
+ import { installShortcuts, isShortcutsInstalled } from '../term-commands/shortcuts.js';
10
+ import { homedir } from 'os';
11
+ import { join } from 'path';
12
+ import { checkCommand } from '../lib/system-detect.js';
9
13
  import {
10
14
  loadGenieConfig,
11
15
  saveGenieConfig,
12
- genieConfigExists,
16
+ markSetupComplete,
17
+ resetConfig,
13
18
  getGenieConfigPath,
19
+ contractPath,
20
+ updateShortcutsConfig,
14
21
  } from '../lib/genie-config.js';
15
- import {
16
- GenieConfig,
17
- PresetName,
18
- PRESET_DESCRIPTIONS,
19
- } from '../types/genie-config.js';
20
- import { describeEnabledHooks } from '../lib/hooks/index.js';
21
- import { installShortcuts, isShortcutsInstalled } from '../term-commands/shortcuts.js';
22
- import { homedir } from 'os';
23
- import { join } from 'path';
22
+ import type { GenieConfig } from '../types/genie-config.js';
23
+
24
+ export interface SetupOptions {
25
+ quick?: boolean;
26
+ shortcuts?: boolean;
27
+ claudio?: boolean;
28
+ terminal?: boolean;
29
+ session?: boolean;
30
+ reset?: boolean;
31
+ show?: boolean;
32
+ }
24
33
 
25
34
  /**
26
35
  * Print the header banner
27
36
  */
28
37
  function printHeader(): void {
29
38
  console.log();
30
- console.log('\x1b[1m\x1b[36m' + '' + '═'.repeat(62) + '╗' + '\x1b[0m');
31
- console.log('\x1b[1m\x1b[36m' + '║ ' + '\x1b[0m\x1b[1m🧞 Genie Setup - Configure Your AI Assistant' + ' '.repeat(16) + '\x1b[36m║\x1b[0m');
32
- console.log('\x1b[1m\x1b[36m' + '' + '═'.repeat(62) + '╝' + '\x1b[0m');
39
+ console.log('\x1b[1m\x1b[36m' + '=' .repeat(64) + '\x1b[0m');
40
+ console.log('\x1b[1m\x1b[36m Genie Setup Wizard\x1b[0m');
41
+ console.log('\x1b[1m\x1b[36m' + '=' .repeat(64) + '\x1b[0m');
33
42
  console.log();
34
43
  }
35
44
 
36
45
  /**
37
- * Print the about hooks section
46
+ * Print a section header
38
47
  */
39
- function printAboutHooks(): void {
40
- console.log('\x1b[1m📚 ABOUT HOOKS\x1b[0m');
41
- console.log('\x1b[2mHooks let you control how the AI uses tools - without wasting\x1b[0m');
42
- console.log('\x1b[2mtokens on prompts! Instead of telling the AI "please use term",\x1b[0m');
43
- console.log('\x1b[2mhooks automatically enforce the behavior.\x1b[0m');
48
+ function printSection(title: string, description?: string): void {
44
49
  console.log();
45
- console.log('\x1b[2m' + '─'.repeat(64) + '\x1b[0m');
50
+ console.log('\x1b[1m' + title + '\x1b[0m');
51
+ if (description) {
52
+ console.log('\x1b[2m' + description + '\x1b[0m');
53
+ }
46
54
  console.log();
47
55
  }
48
56
 
49
- /**
50
- * Print available presets in a nice format
51
- */
52
- function printPresetDescriptions(): void {
53
- console.log('\x1b[1m🔧 AVAILABLE HOOK PRESETS\x1b[0m');
54
- console.log();
57
+ // ============================================================================
58
+ // Prerequisites Check (read-only)
59
+ // ============================================================================
60
+
61
+ async function checkPrerequisites(): Promise<void> {
62
+ printSection('1. Prerequisites Check', 'Checking required tools...');
63
+
64
+ const checks = [
65
+ { name: 'tmux', required: true },
66
+ { name: 'bun', required: true },
67
+ { name: 'claude', required: false, displayName: 'Claude Code CLI' },
68
+ { name: 'jq', required: false },
69
+ ];
70
+
71
+ for (const check of checks) {
72
+ const result = await checkCommand(check.name);
73
+ const displayName = check.displayName || check.name;
74
+ if (result.exists) {
75
+ console.log(` \x1b[32m\u2713\x1b[0m ${displayName} ${result.version ? `(${result.version})` : ''}`);
76
+ } else if (check.required) {
77
+ console.log(` \x1b[31m\u2717\x1b[0m ${displayName} \x1b[2m(required)\x1b[0m`);
78
+ } else {
79
+ console.log(` \x1b[33m!\x1b[0m ${displayName} \x1b[2m(optional)\x1b[0m`);
80
+ }
81
+ }
82
+ }
55
83
 
56
- for (let i = 0; i < PRESET_DESCRIPTIONS.length; i++) {
57
- const preset = PRESET_DESCRIPTIONS[i];
58
- const num = i + 1;
59
- const recommended = preset.recommended ? ' \x1b[32m(Recommended)\x1b[0m' : '';
84
+ // ============================================================================
85
+ // Session Configuration
86
+ // ============================================================================
60
87
 
61
- console.log(`\x1b[1m${num}. ${preset.title}\x1b[0m${recommended}`);
62
- console.log(` ├─ What: ${preset.what}`);
63
- console.log(` ├─ Why: ${preset.why}`);
64
- console.log(` └─ How: ${preset.how}`);
65
- console.log();
88
+ async function configureSession(config: GenieConfig, quick: boolean): Promise<GenieConfig> {
89
+ printSection('2. Session Configuration', 'Configure tmux session settings');
90
+
91
+ if (quick) {
92
+ console.log(` Using defaults: session="${config.session.name}", window="${config.session.defaultWindow}"`);
93
+ return config;
66
94
  }
67
95
 
68
- console.log('\x1b[2m' + '─'.repeat(64) + '\x1b[0m');
69
- console.log();
70
- }
96
+ const sessionName = await input({
97
+ message: 'Session name:',
98
+ default: config.session.name,
99
+ });
71
100
 
72
- /**
73
- * Format preset choice for checkbox
74
- */
75
- function formatPresetChoice(preset: typeof PRESET_DESCRIPTIONS[0], enabled: boolean): {
76
- name: string;
77
- value: PresetName;
78
- checked: boolean;
79
- } {
80
- const recommended = preset.recommended ? ' \x1b[32m(Recommended)\x1b[0m' : '';
81
- return {
82
- name: `${preset.title}${recommended} - ${preset.what}`,
83
- value: preset.name,
84
- checked: enabled,
101
+ const defaultWindow = await input({
102
+ message: 'Default window name:',
103
+ default: config.session.defaultWindow,
104
+ });
105
+
106
+ const autoCreate = await confirm({
107
+ message: 'Auto-create session on connect?',
108
+ default: config.session.autoCreate,
109
+ });
110
+
111
+ config.session = {
112
+ name: sessionName,
113
+ defaultWindow,
114
+ autoCreate,
85
115
  };
86
- }
87
116
 
88
- /**
89
- * Print success message
90
- */
91
- function printSuccess(configPath: string): void {
92
- console.log();
93
- console.log(`\x1b[32m✓ Configuration saved to ${configPath}\x1b[0m`);
94
- console.log();
95
- console.log('\x1b[1m💡 TIP:\x1b[0m Claudio will automatically use these hooks.');
96
- console.log(' Run: \x1b[36mclaudio launch\x1b[0m');
97
- console.log(' Watch: \x1b[36mtmux attach -t genie\x1b[0m');
98
- console.log();
117
+ return config;
99
118
  }
100
119
 
101
- /**
102
- * Print current configuration
103
- */
104
- function printCurrentConfig(config: GenieConfig): void {
105
- const descriptions = describeEnabledHooks(config);
120
+ // ============================================================================
121
+ // Terminal Configuration
122
+ // ============================================================================
106
123
 
107
- if (descriptions.length === 0) {
108
- console.log('\x1b[33mNo hooks currently enabled.\x1b[0m');
109
- } else {
110
- console.log('\x1b[1mCurrently enabled hooks:\x1b[0m');
111
- for (const desc of descriptions) {
112
- console.log(` • ${desc}`);
113
- }
124
+ async function configureTerminal(config: GenieConfig, quick: boolean): Promise<GenieConfig> {
125
+ printSection('3. Terminal Defaults', 'Configure default values for term commands');
126
+
127
+ if (quick) {
128
+ console.log(` Using defaults: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`);
129
+ return config;
114
130
  }
115
- console.log();
116
- }
117
131
 
118
- /**
119
- * Configure sandboxed preset paths
120
- */
121
- async function configureSandbox(config: GenieConfig): Promise<void> {
122
- const currentPaths = config.hooks.sandboxed?.allowedPaths || ['~/projects', '/tmp'];
132
+ const timeoutStr = await input({
133
+ message: 'Exec timeout (milliseconds):',
134
+ default: String(config.terminal.execTimeout),
135
+ validate: (v) => {
136
+ const n = parseInt(v, 10);
137
+ return !isNaN(n) && n > 0 ? true : 'Must be a positive number';
138
+ },
139
+ });
123
140
 
124
- console.log('\x1b[1mSandbox Configuration\x1b[0m');
125
- console.log('\x1b[2mEnter paths where the AI can access files (comma-separated):\x1b[0m');
141
+ const linesStr = await input({
142
+ message: 'Read lines (default for term read):',
143
+ default: String(config.terminal.readLines),
144
+ validate: (v) => {
145
+ const n = parseInt(v, 10);
146
+ return !isNaN(n) && n > 0 ? true : 'Must be a positive number';
147
+ },
148
+ });
126
149
 
127
- const pathsInput = await input({
128
- message: 'Allowed paths:',
129
- default: currentPaths.join(', '),
150
+ const worktreeBase = await input({
151
+ message: 'Worktree base directory:',
152
+ default: config.terminal.worktreeBase,
130
153
  });
131
154
 
132
- const allowedPaths = pathsInput
133
- .split(',')
134
- .map((p) => p.trim())
135
- .filter(Boolean);
155
+ config.terminal = {
156
+ execTimeout: parseInt(timeoutStr, 10),
157
+ readLines: parseInt(linesStr, 10),
158
+ worktreeBase,
159
+ };
136
160
 
137
- config.hooks.sandboxed = { allowedPaths };
161
+ return config;
138
162
  }
139
163
 
140
- /**
141
- * Configure audited preset log path
142
- */
143
- async function configureAudit(config: GenieConfig): Promise<void> {
144
- const currentPath = config.hooks.audited?.logPath || '~/.genie/audit.log';
164
+ // ============================================================================
165
+ // Keyboard Shortcuts
166
+ // ============================================================================
145
167
 
146
- console.log('\x1b[1mAudit Configuration\x1b[0m');
168
+ async function configureShortcuts(config: GenieConfig, quick: boolean): Promise<GenieConfig> {
169
+ printSection('4. Keyboard Shortcuts', 'Warp-like tmux shortcuts for quick navigation');
147
170
 
148
- const logPath = await input({
149
- message: 'Audit log path:',
150
- default: currentPath,
151
- });
152
-
153
- config.hooks.audited = { logPath };
154
- }
171
+ const home = homedir();
172
+ const tmuxConf = join(home, '.tmux.conf');
173
+ const tmuxInstalled = isShortcutsInstalled(tmuxConf);
155
174
 
156
- /**
157
- * Main setup wizard
158
- */
159
- export async function setupCommand(): Promise<void> {
160
- printHeader();
161
- printAboutHooks();
162
- printPresetDescriptions();
175
+ if (tmuxInstalled) {
176
+ console.log(' \x1b[32m\u2713\x1b[0m Tmux shortcuts already installed');
177
+ config.shortcuts.tmuxInstalled = true;
178
+ return config;
179
+ }
163
180
 
164
- // Load existing config or defaults
165
- const config = await loadGenieConfig();
166
- const existingPresets = new Set(config.hooks.enabled);
181
+ console.log(' Available shortcuts:');
182
+ console.log(' \x1b[36mCtrl+T\x1b[0m \u2192 New tab (window)');
183
+ console.log(' \x1b[36mCtrl+S\x1b[0m \u2192 Vertical split');
184
+ console.log(' \x1b[36mCtrl+H\x1b[0m \u2192 Horizontal split');
185
+ console.log();
167
186
 
168
- // If config exists, show current state
169
- if (genieConfigExists()) {
170
- console.log('\x1b[1m📋 CURRENT CONFIGURATION\x1b[0m');
171
- printCurrentConfig(config);
187
+ if (quick) {
188
+ console.log(' Skipped in quick mode. Run \x1b[36mgenie setup --shortcuts\x1b[0m to install.');
189
+ return config;
172
190
  }
173
191
 
174
- // Build choices for checkbox
175
- const choices = PRESET_DESCRIPTIONS.map((preset) =>
176
- formatPresetChoice(preset, existingPresets.has(preset.name))
177
- );
178
-
179
- // Prompt for preset selection
180
- const selectedPresets = await checkbox<PresetName>({
181
- message: 'Select hooks to enable (space to toggle, enter to confirm):',
182
- choices,
192
+ const installChoice = await confirm({
193
+ message: 'Install tmux keyboard shortcuts?',
194
+ default: false,
183
195
  });
184
196
 
185
- // Update config with selections
186
- config.hooks.enabled = selectedPresets;
187
-
188
- // If sandboxed is enabled, configure it
189
- if (selectedPresets.includes('sandboxed')) {
197
+ if (installChoice) {
190
198
  console.log();
191
- await configureSandbox(config);
199
+ await installShortcuts();
200
+ config.shortcuts.tmuxInstalled = true;
201
+ await updateShortcutsConfig({ tmuxInstalled: true });
202
+ } else {
203
+ console.log(' Skipped. Run \x1b[36mgenie shortcuts install\x1b[0m later.');
192
204
  }
193
205
 
194
- // If audited is enabled, optionally configure it
195
- if (selectedPresets.includes('audited')) {
196
- console.log();
197
- const customAudit = await confirm({
198
- message: 'Customize audit log path?',
199
- default: false,
200
- });
201
- if (customAudit) {
202
- await configureAudit(config);
203
- }
206
+ return config;
207
+ }
208
+
209
+ // ============================================================================
210
+ // Claudio Integration
211
+ // ============================================================================
212
+
213
+ async function configureClaudio(config: GenieConfig, quick: boolean): Promise<GenieConfig> {
214
+ printSection('5. Claudio Integration', 'LLM router profile management');
215
+
216
+ const claudeCheck = await checkCommand('claude');
217
+
218
+ if (!claudeCheck.exists) {
219
+ console.log(' \x1b[33m!\x1b[0m Claude Code CLI not found. Skipping claudio integration.');
220
+ return config;
204
221
  }
205
222
 
206
- // Save configuration
207
- await saveGenieConfig(config);
223
+ if (quick) {
224
+ console.log(' Skipped in quick mode. Run \x1b[36mclaudio setup\x1b[0m to configure.');
225
+ return config;
226
+ }
208
227
 
209
- printSuccess(getGenieConfigPath());
228
+ const enableClaudio = await confirm({
229
+ message: 'Configure Claudio API profiles?',
230
+ default: false,
231
+ });
210
232
 
211
- // Show what was configured
212
- if (selectedPresets.length > 0) {
213
- console.log('\x1b[1mEnabled hooks:\x1b[0m');
214
- const descriptions = describeEnabledHooks(config);
215
- for (const desc of descriptions) {
216
- console.log(` \x1b[32m✓\x1b[0m ${desc}`);
217
- }
233
+ if (enableClaudio) {
234
+ config.claudio = { enabled: true };
218
235
  console.log();
236
+ console.log(' Run \x1b[36mclaudio setup\x1b[0m to configure API profiles.');
237
+ } else {
238
+ console.log(' Skipped. Run \x1b[36mclaudio setup\x1b[0m later.');
219
239
  }
220
240
 
221
- // Offer to install tmux shortcuts
222
- await offerShortcutsInstall();
241
+ return config;
223
242
  }
224
243
 
225
- /**
226
- * Offer to install tmux keyboard shortcuts
227
- */
228
- async function offerShortcutsInstall(): Promise<void> {
229
- // Check if already installed
230
- const home = homedir();
231
- const tmuxConf = join(home, '.tmux.conf');
244
+ // ============================================================================
245
+ // Debug Options
246
+ // ============================================================================
232
247
 
233
- if (isShortcutsInstalled(tmuxConf)) {
234
- console.log('\x1b[2m✓ Tmux shortcuts already installed\x1b[0m');
235
- console.log();
236
- return;
248
+ async function configureDebug(config: GenieConfig, quick: boolean): Promise<GenieConfig> {
249
+ printSection('6. Debug Options', 'Logging and debugging settings');
250
+
251
+ if (quick) {
252
+ console.log(' Using defaults: tmuxDebug=false, verbose=false');
253
+ return config;
237
254
  }
238
255
 
239
- console.log('\x1b[2m' + '─'.repeat(64) + '\x1b[0m');
240
- console.log();
241
- console.log('\x1b[1m⌨️ KEYBOARD SHORTCUTS\x1b[0m');
242
- console.log('\x1b[2mOptional: Install Warp-like tmux shortcuts for quick navigation:\x1b[0m');
243
- console.log(' • Ctrl+T → New tab (window)');
244
- console.log(' • Ctrl+S → Vertical split');
245
- console.log(' • Alt+S → Horizontal split');
246
- console.log();
256
+ const tmuxDebug = await confirm({
257
+ message: 'Enable tmux debug logging?',
258
+ default: config.logging.tmuxDebug,
259
+ });
247
260
 
248
- const installShortcutsChoice = await confirm({
249
- message: 'Install tmux keyboard shortcuts?',
250
- default: false,
261
+ const verbose = await confirm({
262
+ message: 'Enable verbose mode?',
263
+ default: config.logging.verbose,
251
264
  });
252
265
 
253
- if (installShortcutsChoice) {
254
- console.log();
255
- await installShortcuts();
256
- } else {
257
- console.log();
258
- console.log('\x1b[2mSkipped. Run \x1b[0m\x1b[36mgenie shortcuts install\x1b[0m\x1b[2m later to add them.\x1b[0m');
259
- console.log();
260
- }
266
+ config.logging = {
267
+ tmuxDebug,
268
+ verbose,
269
+ };
270
+
271
+ return config;
261
272
  }
262
273
 
263
- /**
264
- * Quick setup with recommended defaults
265
- */
266
- export async function quickSetupCommand(): Promise<void> {
267
- console.log('\x1b[1m🧞 Quick Setup - Using recommended defaults\x1b[0m');
274
+ // ============================================================================
275
+ // Summary and Save
276
+ // ============================================================================
277
+
278
+ async function showSummaryAndSave(config: GenieConfig): Promise<void> {
279
+ printSection('Summary', 'Configuration will be saved to ' + contractPath(getGenieConfigPath()));
280
+
281
+ console.log(` Session: \x1b[36m${config.session.name}\x1b[0m (window: ${config.session.defaultWindow})`);
282
+ console.log(` Terminal: timeout=${config.terminal.execTimeout}ms, lines=${config.terminal.readLines}`);
283
+ console.log(` Shortcuts: ${config.shortcuts.tmuxInstalled ? '\x1b[32minstalled\x1b[0m' : '\x1b[2mnot installed\x1b[0m'}`);
284
+ console.log(` Claudio: ${config.claudio?.enabled ? '\x1b[32menabled\x1b[0m' : '\x1b[2mnot configured\x1b[0m'}`);
285
+ console.log(` Debug: tmux=${config.logging.tmuxDebug}, verbose=${config.logging.verbose}`);
268
286
  console.log();
269
287
 
288
+ // Save config
289
+ config.setupComplete = true;
290
+ config.lastSetupAt = new Date().toISOString();
291
+ await saveGenieConfig(config);
292
+
293
+ console.log('\x1b[32m\u2713 Configuration saved!\x1b[0m');
294
+ }
295
+
296
+ // ============================================================================
297
+ // Show Current Config
298
+ // ============================================================================
299
+
300
+ async function showCurrentConfig(): Promise<void> {
270
301
  const config = await loadGenieConfig();
271
302
 
272
- // Enable recommended presets
273
- config.hooks.enabled = ['collaborative', 'audited'];
303
+ console.log();
304
+ console.log('\x1b[1mCurrent Genie Configuration\x1b[0m');
305
+ console.log('\x1b[2m' + contractPath(getGenieConfigPath()) + '\x1b[0m');
306
+ console.log();
307
+ console.log(JSON.stringify(config, null, 2));
308
+ console.log();
309
+ }
274
310
 
275
- await saveGenieConfig(config);
311
+ // ============================================================================
312
+ // Print Next Steps
313
+ // ============================================================================
276
314
 
277
- console.log('\x1b[32m✓ Enabled:\x1b[0m collaborative, audited');
315
+ function printNextSteps(): void {
278
316
  console.log();
279
- console.log('Run \x1b[36mgenie setup\x1b[0m to customize further.');
317
+ console.log('\x1b[1mNext Steps:\x1b[0m');
318
+ console.log();
319
+ console.log(' Start a session: \x1b[36mclaudio launch\x1b[0m');
320
+ console.log(' Watch AI work: \x1b[36mtmux attach -t genie\x1b[0m');
321
+ console.log(' Check health: \x1b[36mgenie doctor\x1b[0m');
280
322
  console.log();
281
323
  }
282
324
 
325
+ // ============================================================================
326
+ // Main Setup Command
327
+ // ============================================================================
328
+
329
+ export async function setupCommand(options: SetupOptions = {}): Promise<void> {
330
+ // Handle --show flag
331
+ if (options.show) {
332
+ await showCurrentConfig();
333
+ return;
334
+ }
335
+
336
+ // Handle --reset flag
337
+ if (options.reset) {
338
+ await resetConfig();
339
+ console.log('\x1b[32m\u2713 Configuration reset to defaults.\x1b[0m');
340
+ console.log();
341
+ return;
342
+ }
343
+
344
+ // Load existing config
345
+ let config = await loadGenieConfig();
346
+
347
+ // Handle section-specific flags
348
+ if (options.shortcuts) {
349
+ printHeader();
350
+ await configureShortcuts(config, false);
351
+ await markSetupComplete();
352
+ return;
353
+ }
354
+
355
+ if (options.terminal) {
356
+ printHeader();
357
+ config = await configureTerminal(config, false);
358
+ await saveGenieConfig(config);
359
+ console.log('\x1b[32m\u2713 Terminal configuration saved.\x1b[0m');
360
+ return;
361
+ }
362
+
363
+ if (options.session) {
364
+ printHeader();
365
+ config = await configureSession(config, false);
366
+ await saveGenieConfig(config);
367
+ console.log('\x1b[32m\u2713 Session configuration saved.\x1b[0m');
368
+ return;
369
+ }
370
+
371
+ if (options.claudio) {
372
+ printHeader();
373
+ await configureClaudio(config, false);
374
+ await markSetupComplete();
375
+ return;
376
+ }
377
+
378
+ // Full wizard
379
+ const quick = options.quick ?? false;
380
+
381
+ printHeader();
382
+
383
+ if (quick) {
384
+ console.log('\x1b[2mQuick mode: accepting all defaults\x1b[0m');
385
+ }
386
+
387
+ // Run all sections
388
+ await checkPrerequisites();
389
+ config = await configureSession(config, quick);
390
+ config = await configureTerminal(config, quick);
391
+ config = await configureShortcuts(config, quick);
392
+ config = await configureClaudio(config, quick);
393
+ config = await configureDebug(config, quick);
394
+
395
+ // Save and show summary
396
+ await showSummaryAndSave(config);
397
+
398
+ // Print next steps
399
+ printNextSteps();
400
+ }