@automagik/genie 0.260202.453 → 0.260202.1607
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/dist/claudio.js +44 -45
- package/dist/genie.js +58 -135
- package/dist/term.js +71 -66
- package/install.sh +43 -7
- package/package.json +1 -1
- package/src/claudio.ts +31 -21
- package/src/commands/launch.ts +12 -68
- package/src/genie-commands/doctor.ts +327 -0
- package/src/genie-commands/setup.ts +317 -199
- package/src/genie-commands/uninstall.ts +176 -0
- package/src/genie.ts +24 -44
- package/src/lib/claude-settings.ts +22 -64
- package/src/lib/genie-config.ts +169 -57
- package/src/lib/version.ts +1 -1
- package/src/term-commands/exec.ts +28 -6
- package/src/term-commands/read.ts +6 -1
- package/src/term-commands/shortcuts.ts +14 -14
- package/src/term.ts +12 -2
- package/src/types/genie-config.ts +49 -81
- package/src/genie-commands/hooks.ts +0 -317
- package/src/lib/hook-script.ts +0 -263
- package/src/lib/hooks/compose.ts +0 -72
- package/src/lib/hooks/index.ts +0 -163
- package/src/lib/hooks/presets/audited.ts +0 -191
- package/src/lib/hooks/presets/collaborative.ts +0 -143
- package/src/lib/hooks/presets/sandboxed.ts +0 -153
- package/src/lib/hooks/presets/supervised.ts +0 -66
- 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
|
|
5
|
-
*
|
|
4
|
+
* Interactive wizard for configuring genie settings.
|
|
5
|
+
* Supports full wizard, quick mode, and section-specific setup.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
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
|
-
|
|
16
|
+
markSetupComplete,
|
|
17
|
+
resetConfig,
|
|
13
18
|
getGenieConfigPath,
|
|
19
|
+
contractPath,
|
|
20
|
+
updateShortcutsConfig,
|
|
14
21
|
} from '../lib/genie-config.js';
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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' + '
|
|
31
|
-
console.log('\x1b[1m\x1b[36m
|
|
32
|
-
console.log('\x1b[1m\x1b[36m' + '
|
|
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
|
|
46
|
+
* Print a section header
|
|
38
47
|
*/
|
|
39
|
-
function
|
|
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[
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const recommended = preset.recommended ? ' \x1b[32m(Recommended)\x1b[0m' : '';
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// Session Configuration
|
|
86
|
+
// ============================================================================
|
|
60
87
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
const sessionName = await input({
|
|
97
|
+
message: 'Session name:',
|
|
98
|
+
default: config.session.name,
|
|
99
|
+
});
|
|
71
100
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
function printCurrentConfig(config: GenieConfig): void {
|
|
105
|
-
const descriptions = describeEnabledHooks(config);
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Terminal Configuration
|
|
122
|
+
// ============================================================================
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
|
128
|
-
message: '
|
|
129
|
-
default:
|
|
150
|
+
const worktreeBase = await input({
|
|
151
|
+
message: 'Worktree base directory:',
|
|
152
|
+
default: config.terminal.worktreeBase,
|
|
130
153
|
});
|
|
131
154
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
config.terminal = {
|
|
156
|
+
execTimeout: parseInt(timeoutStr, 10),
|
|
157
|
+
readLines: parseInt(linesStr, 10),
|
|
158
|
+
worktreeBase,
|
|
159
|
+
};
|
|
136
160
|
|
|
137
|
-
config
|
|
161
|
+
return config;
|
|
138
162
|
}
|
|
139
163
|
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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
|
-
|
|
228
|
+
const enableClaudio = await confirm({
|
|
229
|
+
message: 'Configure Claudio API profiles?',
|
|
230
|
+
default: false,
|
|
231
|
+
});
|
|
210
232
|
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
222
|
-
await offerShortcutsInstall();
|
|
241
|
+
return config;
|
|
223
242
|
}
|
|
224
243
|
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
|
249
|
-
message: '
|
|
250
|
-
default:
|
|
261
|
+
const verbose = await confirm({
|
|
262
|
+
message: 'Enable verbose mode?',
|
|
263
|
+
default: config.logging.verbose,
|
|
251
264
|
});
|
|
252
265
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
console.log();
|
|
260
|
-
}
|
|
266
|
+
config.logging = {
|
|
267
|
+
tmuxDebug,
|
|
268
|
+
verbose,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return config;
|
|
261
272
|
}
|
|
262
273
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
273
|
-
|
|
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
|
-
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// Print Next Steps
|
|
313
|
+
// ============================================================================
|
|
276
314
|
|
|
277
|
-
|
|
315
|
+
function printNextSteps(): void {
|
|
278
316
|
console.log();
|
|
279
|
-
console.log('
|
|
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
|
+
}
|