@wundr.io/cli 1.0.0 → 1.0.1

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 (166) hide show
  1. package/README.md +696 -280
  2. package/package.json +4 -4
  3. package/src/commands/computer-setup-commands.ts +160 -0
  4. package/src/tests/computer-setup-integration.test.ts +439 -0
  5. package/src/utils/backup-rollback-manager.ts +361 -0
  6. package/src/utils/claude-config-installer.ts +732 -0
  7. package/dist/ai/ai-service.d.ts +0 -152
  8. package/dist/ai/ai-service.d.ts.map +0 -1
  9. package/dist/ai/ai-service.js +0 -430
  10. package/dist/ai/ai-service.js.map +0 -1
  11. package/dist/ai/claude-client.d.ts +0 -130
  12. package/dist/ai/claude-client.d.ts.map +0 -1
  13. package/dist/ai/claude-client.js +0 -339
  14. package/dist/ai/claude-client.js.map +0 -1
  15. package/dist/ai/conversation-manager.d.ts +0 -164
  16. package/dist/ai/conversation-manager.d.ts.map +0 -1
  17. package/dist/ai/conversation-manager.js +0 -612
  18. package/dist/ai/conversation-manager.js.map +0 -1
  19. package/dist/ai/index.d.ts +0 -5
  20. package/dist/ai/index.d.ts.map +0 -1
  21. package/dist/ai/index.js +0 -8
  22. package/dist/ai/index.js.map +0 -1
  23. package/dist/cli.d.ts +0 -36
  24. package/dist/cli.d.ts.map +0 -1
  25. package/dist/cli.js +0 -173
  26. package/dist/cli.js.map +0 -1
  27. package/dist/commands/ai.d.ts +0 -89
  28. package/dist/commands/ai.d.ts.map +0 -1
  29. package/dist/commands/ai.js +0 -735
  30. package/dist/commands/ai.js.map +0 -1
  31. package/dist/commands/analyze-optimized.d.ts +0 -14
  32. package/dist/commands/analyze-optimized.d.ts.map +0 -1
  33. package/dist/commands/analyze-optimized.js +0 -437
  34. package/dist/commands/analyze-optimized.js.map +0 -1
  35. package/dist/commands/analyze.d.ts +0 -65
  36. package/dist/commands/analyze.d.ts.map +0 -1
  37. package/dist/commands/analyze.js +0 -435
  38. package/dist/commands/analyze.js.map +0 -1
  39. package/dist/commands/batch.d.ts +0 -71
  40. package/dist/commands/batch.d.ts.map +0 -1
  41. package/dist/commands/batch.js +0 -738
  42. package/dist/commands/batch.js.map +0 -1
  43. package/dist/commands/chat.d.ts +0 -71
  44. package/dist/commands/chat.d.ts.map +0 -1
  45. package/dist/commands/chat.js +0 -674
  46. package/dist/commands/chat.js.map +0 -1
  47. package/dist/commands/claude-init.d.ts +0 -28
  48. package/dist/commands/claude-init.d.ts.map +0 -1
  49. package/dist/commands/claude-init.js +0 -587
  50. package/dist/commands/claude-init.js.map +0 -1
  51. package/dist/commands/claude-setup.d.ts +0 -32
  52. package/dist/commands/claude-setup.d.ts.map +0 -1
  53. package/dist/commands/claude-setup.js +0 -570
  54. package/dist/commands/claude-setup.js.map +0 -1
  55. package/dist/commands/computer-setup-commands.d.ts +0 -39
  56. package/dist/commands/computer-setup-commands.d.ts.map +0 -1
  57. package/dist/commands/computer-setup-commands.js +0 -563
  58. package/dist/commands/computer-setup-commands.js.map +0 -1
  59. package/dist/commands/computer-setup.d.ts +0 -7
  60. package/dist/commands/computer-setup.d.ts.map +0 -1
  61. package/dist/commands/computer-setup.js +0 -481
  62. package/dist/commands/computer-setup.js.map +0 -1
  63. package/dist/commands/create-command.d.ts +0 -7
  64. package/dist/commands/create-command.d.ts.map +0 -1
  65. package/dist/commands/create-command.js +0 -158
  66. package/dist/commands/create-command.js.map +0 -1
  67. package/dist/commands/create.d.ts +0 -74
  68. package/dist/commands/create.d.ts.map +0 -1
  69. package/dist/commands/create.js +0 -556
  70. package/dist/commands/create.js.map +0 -1
  71. package/dist/commands/dashboard.d.ts +0 -91
  72. package/dist/commands/dashboard.d.ts.map +0 -1
  73. package/dist/commands/dashboard.js +0 -537
  74. package/dist/commands/dashboard.js.map +0 -1
  75. package/dist/commands/govern.d.ts +0 -70
  76. package/dist/commands/govern.d.ts.map +0 -1
  77. package/dist/commands/govern.js +0 -480
  78. package/dist/commands/govern.js.map +0 -1
  79. package/dist/commands/init.d.ts +0 -55
  80. package/dist/commands/init.d.ts.map +0 -1
  81. package/dist/commands/init.js +0 -584
  82. package/dist/commands/init.js.map +0 -1
  83. package/dist/commands/performance-optimizer.d.ts +0 -30
  84. package/dist/commands/performance-optimizer.d.ts.map +0 -1
  85. package/dist/commands/performance-optimizer.js +0 -649
  86. package/dist/commands/performance-optimizer.js.map +0 -1
  87. package/dist/commands/plugins.d.ts +0 -87
  88. package/dist/commands/plugins.d.ts.map +0 -1
  89. package/dist/commands/plugins.js +0 -685
  90. package/dist/commands/plugins.js.map +0 -1
  91. package/dist/commands/setup.d.ts +0 -29
  92. package/dist/commands/setup.d.ts.map +0 -1
  93. package/dist/commands/setup.js +0 -399
  94. package/dist/commands/setup.js.map +0 -1
  95. package/dist/commands/test-init.d.ts +0 -9
  96. package/dist/commands/test-init.d.ts.map +0 -1
  97. package/dist/commands/test-init.js +0 -222
  98. package/dist/commands/test-init.js.map +0 -1
  99. package/dist/commands/test.d.ts +0 -25
  100. package/dist/commands/test.d.ts.map +0 -1
  101. package/dist/commands/test.js +0 -217
  102. package/dist/commands/test.js.map +0 -1
  103. package/dist/commands/watch.d.ts +0 -76
  104. package/dist/commands/watch.d.ts.map +0 -1
  105. package/dist/commands/watch.js +0 -610
  106. package/dist/commands/watch.js.map +0 -1
  107. package/dist/context/context-manager.d.ts +0 -155
  108. package/dist/context/context-manager.d.ts.map +0 -1
  109. package/dist/context/context-manager.js +0 -383
  110. package/dist/context/context-manager.js.map +0 -1
  111. package/dist/context/index.d.ts +0 -3
  112. package/dist/context/index.d.ts.map +0 -1
  113. package/dist/context/index.js +0 -6
  114. package/dist/context/index.js.map +0 -1
  115. package/dist/context/session-manager.d.ts +0 -207
  116. package/dist/context/session-manager.d.ts.map +0 -1
  117. package/dist/context/session-manager.js +0 -682
  118. package/dist/context/session-manager.js.map +0 -1
  119. package/dist/index.d.ts +0 -8
  120. package/dist/index.d.ts.map +0 -1
  121. package/dist/index.js +0 -51
  122. package/dist/index.js.map +0 -1
  123. package/dist/interactive/interactive-mode.d.ts +0 -76
  124. package/dist/interactive/interactive-mode.d.ts.map +0 -1
  125. package/dist/interactive/interactive-mode.js +0 -730
  126. package/dist/interactive/interactive-mode.js.map +0 -1
  127. package/dist/nlp/command-mapper.d.ts +0 -174
  128. package/dist/nlp/command-mapper.d.ts.map +0 -1
  129. package/dist/nlp/command-mapper.js +0 -623
  130. package/dist/nlp/command-mapper.js.map +0 -1
  131. package/dist/nlp/command-parser.d.ts +0 -106
  132. package/dist/nlp/command-parser.d.ts.map +0 -1
  133. package/dist/nlp/command-parser.js +0 -416
  134. package/dist/nlp/command-parser.js.map +0 -1
  135. package/dist/nlp/index.d.ts +0 -5
  136. package/dist/nlp/index.d.ts.map +0 -1
  137. package/dist/nlp/index.js +0 -8
  138. package/dist/nlp/index.js.map +0 -1
  139. package/dist/nlp/intent-classifier.d.ts +0 -59
  140. package/dist/nlp/intent-classifier.d.ts.map +0 -1
  141. package/dist/nlp/intent-classifier.js +0 -384
  142. package/dist/nlp/intent-classifier.js.map +0 -1
  143. package/dist/nlp/intent-parser.d.ts +0 -152
  144. package/dist/nlp/intent-parser.d.ts.map +0 -1
  145. package/dist/nlp/intent-parser.js +0 -739
  146. package/dist/nlp/intent-parser.js.map +0 -1
  147. package/dist/plugins/plugin-manager.d.ts +0 -120
  148. package/dist/plugins/plugin-manager.d.ts.map +0 -1
  149. package/dist/plugins/plugin-manager.js +0 -595
  150. package/dist/plugins/plugin-manager.js.map +0 -1
  151. package/dist/types/index.d.ts +0 -224
  152. package/dist/types/index.d.ts.map +0 -1
  153. package/dist/types/index.js +0 -3
  154. package/dist/types/index.js.map +0 -1
  155. package/dist/utils/config-manager.d.ts +0 -73
  156. package/dist/utils/config-manager.d.ts.map +0 -1
  157. package/dist/utils/config-manager.js +0 -339
  158. package/dist/utils/config-manager.js.map +0 -1
  159. package/dist/utils/error-handler.d.ts +0 -46
  160. package/dist/utils/error-handler.d.ts.map +0 -1
  161. package/dist/utils/error-handler.js +0 -169
  162. package/dist/utils/error-handler.js.map +0 -1
  163. package/dist/utils/logger.d.ts +0 -25
  164. package/dist/utils/logger.d.ts.map +0 -1
  165. package/dist/utils/logger.js +0 -94
  166. package/dist/utils/logger.js.map +0 -1
@@ -0,0 +1,732 @@
1
+ /**
2
+ * Claude Code Configuration Installer
3
+ * Handles installation of CLAUDE.md, hooks, conventions, and agent templates
4
+ */
5
+
6
+ import * as fs from 'fs/promises';
7
+ import * as path from 'path';
8
+ import { existsSync } from 'fs';
9
+ import chalk from 'chalk';
10
+ import ora from 'ora';
11
+ import { logger } from './logger';
12
+ import { BackupRollbackManager } from './backup-rollback-manager';
13
+
14
+ export interface ClaudeConfigOptions {
15
+ claudeDir?: string;
16
+ sourceDir?: string;
17
+ dryRun?: boolean;
18
+ skipBackup?: boolean;
19
+ overwrite?: boolean;
20
+ verbose?: boolean;
21
+ }
22
+
23
+ export interface InstallResult {
24
+ success: boolean;
25
+ installed: string[];
26
+ skipped: string[];
27
+ errors: Array<{ file: string; error: string }>;
28
+ backupId?: string;
29
+ }
30
+
31
+ export class ClaudeConfigInstaller {
32
+ private claudeDir: string;
33
+ private sourceDir: string;
34
+ private backupManager: BackupRollbackManager;
35
+ private homeDir: string;
36
+
37
+ constructor(options: ClaudeConfigOptions = {}) {
38
+ this.homeDir = process.env.HOME || process.env.USERPROFILE || '';
39
+ this.claudeDir = options.claudeDir || path.join(this.homeDir, '.claude');
40
+ this.sourceDir = options.sourceDir || process.cwd();
41
+ this.backupManager = new BackupRollbackManager();
42
+ }
43
+
44
+ /**
45
+ * Initialize installer
46
+ */
47
+ async initialize(): Promise<void> {
48
+ await this.backupManager.initialize();
49
+
50
+ // Create Claude directory structure
51
+ await this.createDirectoryStructure();
52
+ }
53
+
54
+ /**
55
+ * Install all Claude Code configurations
56
+ */
57
+ async install(options: ClaudeConfigOptions = {}): Promise<InstallResult> {
58
+ const { dryRun = false, skipBackup = false, overwrite = false, verbose = false } = options;
59
+
60
+ const result: InstallResult = {
61
+ success: false,
62
+ installed: [],
63
+ skipped: [],
64
+ errors: [],
65
+ };
66
+
67
+ try {
68
+ console.log(chalk.cyan('\nšŸ”§ Installing Claude Code Configuration\n'));
69
+
70
+ // Create backup of existing configs
71
+ if (!skipBackup && !dryRun) {
72
+ const existingFiles = await this.getExistingConfigFiles();
73
+ if (existingFiles.length > 0) {
74
+ const spinner = ora('Creating backup of existing configurations...').start();
75
+ const backup = await this.backupManager.createBackup(
76
+ existingFiles,
77
+ 'Pre-installation backup'
78
+ );
79
+ result.backupId = backup.backupId;
80
+ spinner.succeed(`Backup created: ${backup.backupId}`);
81
+ }
82
+ }
83
+
84
+ // Install CLAUDE.md
85
+ await this.installClaudeMd(result, { dryRun, overwrite, verbose });
86
+
87
+ // Install hooks
88
+ await this.installHooks(result, { dryRun, overwrite, verbose });
89
+
90
+ // Install conventions
91
+ await this.installConventions(result, { dryRun, overwrite, verbose });
92
+
93
+ // Install agent templates
94
+ await this.installAgentTemplates(result, { dryRun, overwrite, verbose });
95
+
96
+ // Install git-worktree workflows
97
+ await this.installGitWorktreeWorkflows(result, { dryRun, overwrite, verbose });
98
+
99
+ // Install validation scripts
100
+ await this.installValidationScripts(result, { dryRun, overwrite, verbose });
101
+
102
+ result.success = result.errors.length === 0;
103
+
104
+ // Display summary
105
+ this.displayInstallSummary(result, dryRun);
106
+
107
+ return result;
108
+ } catch (error) {
109
+ logger.error('Installation failed', error);
110
+ result.errors.push({
111
+ file: 'general',
112
+ error: error instanceof Error ? error.message : String(error)
113
+ });
114
+ return result;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Install enhanced CLAUDE.md to ~/.claude/
120
+ */
121
+ private async installClaudeMd(
122
+ result: InstallResult,
123
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
124
+ ): Promise<void> {
125
+ const spinner = ora('Installing CLAUDE.md...').start();
126
+
127
+ try {
128
+ const sourcePath = path.join(this.sourceDir, 'CLAUDE.md');
129
+ const targetPath = path.join(this.claudeDir, 'CLAUDE.md');
130
+
131
+ if (!existsSync(sourcePath)) {
132
+ spinner.warn('CLAUDE.md not found in source directory');
133
+ result.skipped.push('CLAUDE.md');
134
+ return;
135
+ }
136
+
137
+ if (existsSync(targetPath) && !options.overwrite) {
138
+ if (options.verbose) {
139
+ spinner.info('CLAUDE.md already exists (use --overwrite to replace)');
140
+ }
141
+ result.skipped.push('CLAUDE.md');
142
+ return;
143
+ }
144
+
145
+ if (options.dryRun) {
146
+ spinner.info('Would install CLAUDE.md');
147
+ result.installed.push('CLAUDE.md (dry-run)');
148
+ return;
149
+ }
150
+
151
+ await fs.copyFile(sourcePath, targetPath);
152
+ spinner.succeed('CLAUDE.md installed');
153
+ result.installed.push('CLAUDE.md');
154
+
155
+ logger.info('CLAUDE.md installed', { target: targetPath });
156
+ } catch (error) {
157
+ spinner.fail('Failed to install CLAUDE.md');
158
+ result.errors.push({
159
+ file: 'CLAUDE.md',
160
+ error: error instanceof Error ? error.message : String(error)
161
+ });
162
+ logger.error('CLAUDE.md installation failed', error);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Install hooks configuration
168
+ */
169
+ private async installHooks(
170
+ result: InstallResult,
171
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
172
+ ): Promise<void> {
173
+ const spinner = ora('Installing hooks...').start();
174
+
175
+ try {
176
+ const hooksDir = path.join(this.claudeDir, 'hooks');
177
+ await fs.mkdir(hooksDir, { recursive: true });
178
+
179
+ const hooks = this.generateHooksConfig();
180
+
181
+ for (const [hookName, hookContent] of Object.entries(hooks)) {
182
+ const hookPath = path.join(hooksDir, hookName);
183
+
184
+ if (existsSync(hookPath) && !options.overwrite) {
185
+ result.skipped.push(`hooks/${hookName}`);
186
+ continue;
187
+ }
188
+
189
+ if (options.dryRun) {
190
+ result.installed.push(`hooks/${hookName} (dry-run)`);
191
+ continue;
192
+ }
193
+
194
+ await fs.writeFile(hookPath, hookContent);
195
+ await fs.chmod(hookPath, 0o755); // Make executable
196
+ result.installed.push(`hooks/${hookName}`);
197
+ }
198
+
199
+ spinner.succeed(`Hooks installed (${Object.keys(hooks).length} files)`);
200
+ logger.info('Hooks installed', { count: Object.keys(hooks).length });
201
+ } catch (error) {
202
+ spinner.fail('Failed to install hooks');
203
+ result.errors.push({
204
+ file: 'hooks',
205
+ error: error instanceof Error ? error.message : String(error)
206
+ });
207
+ logger.error('Hooks installation failed', error);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Install conventions
213
+ */
214
+ private async installConventions(
215
+ result: InstallResult,
216
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
217
+ ): Promise<void> {
218
+ const spinner = ora('Installing conventions...').start();
219
+
220
+ try {
221
+ const conventionsPath = path.join(this.claudeDir, 'conventions.json');
222
+ const conventions = this.generateConventions();
223
+
224
+ if (existsSync(conventionsPath) && !options.overwrite) {
225
+ spinner.info('Conventions already exist');
226
+ result.skipped.push('conventions.json');
227
+ return;
228
+ }
229
+
230
+ if (options.dryRun) {
231
+ spinner.info('Would install conventions');
232
+ result.installed.push('conventions.json (dry-run)');
233
+ return;
234
+ }
235
+
236
+ await fs.writeFile(conventionsPath, JSON.stringify(conventions, null, 2));
237
+ spinner.succeed('Conventions installed');
238
+ result.installed.push('conventions.json');
239
+
240
+ logger.info('Conventions installed', { path: conventionsPath });
241
+ } catch (error) {
242
+ spinner.fail('Failed to install conventions');
243
+ result.errors.push({
244
+ file: 'conventions.json',
245
+ error: error instanceof Error ? error.message : String(error)
246
+ });
247
+ logger.error('Conventions installation failed', error);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Install agent templates
253
+ */
254
+ private async installAgentTemplates(
255
+ result: InstallResult,
256
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
257
+ ): Promise<void> {
258
+ const spinner = ora('Installing agent templates...').start();
259
+
260
+ try {
261
+ const agentsDir = path.join(this.claudeDir, 'agents');
262
+ await fs.mkdir(agentsDir, { recursive: true });
263
+
264
+ const templates = this.generateAgentTemplates();
265
+
266
+ for (const [agentName, agentConfig] of Object.entries(templates)) {
267
+ const agentPath = path.join(agentsDir, `${agentName}.json`);
268
+
269
+ if (existsSync(agentPath) && !options.overwrite) {
270
+ result.skipped.push(`agents/${agentName}.json`);
271
+ continue;
272
+ }
273
+
274
+ if (options.dryRun) {
275
+ result.installed.push(`agents/${agentName}.json (dry-run)`);
276
+ continue;
277
+ }
278
+
279
+ await fs.writeFile(agentPath, JSON.stringify(agentConfig, null, 2));
280
+ result.installed.push(`agents/${agentName}.json`);
281
+ }
282
+
283
+ spinner.succeed(`Agent templates installed (${Object.keys(templates).length} templates)`);
284
+ logger.info('Agent templates installed', { count: Object.keys(templates).length });
285
+ } catch (error) {
286
+ spinner.fail('Failed to install agent templates');
287
+ result.errors.push({
288
+ file: 'agent-templates',
289
+ error: error instanceof Error ? error.message : String(error)
290
+ });
291
+ logger.error('Agent templates installation failed', error);
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Install git-worktree workflows
297
+ */
298
+ private async installGitWorktreeWorkflows(
299
+ result: InstallResult,
300
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
301
+ ): Promise<void> {
302
+ const spinner = ora('Installing git-worktree workflows...').start();
303
+
304
+ try {
305
+ const workflowsDir = path.join(this.claudeDir, 'workflows');
306
+ await fs.mkdir(workflowsDir, { recursive: true });
307
+
308
+ const workflows = this.generateGitWorktreeWorkflows();
309
+
310
+ for (const [workflowName, workflowContent] of Object.entries(workflows)) {
311
+ const workflowPath = path.join(workflowsDir, `${workflowName}.json`);
312
+
313
+ if (existsSync(workflowPath) && !options.overwrite) {
314
+ result.skipped.push(`workflows/${workflowName}.json`);
315
+ continue;
316
+ }
317
+
318
+ if (options.dryRun) {
319
+ result.installed.push(`workflows/${workflowName}.json (dry-run)`);
320
+ continue;
321
+ }
322
+
323
+ await fs.writeFile(workflowPath, JSON.stringify(workflowContent, null, 2));
324
+ result.installed.push(`workflows/${workflowName}.json`);
325
+ }
326
+
327
+ spinner.succeed(`Git-worktree workflows installed (${Object.keys(workflows).length} workflows)`);
328
+ logger.info('Git-worktree workflows installed', { count: Object.keys(workflows).length });
329
+ } catch (error) {
330
+ spinner.fail('Failed to install git-worktree workflows');
331
+ result.errors.push({
332
+ file: 'git-worktree-workflows',
333
+ error: error instanceof Error ? error.message : String(error)
334
+ });
335
+ logger.error('Git-worktree workflows installation failed', error);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Install validation scripts
341
+ */
342
+ private async installValidationScripts(
343
+ result: InstallResult,
344
+ options: { dryRun: boolean; overwrite: boolean; verbose: boolean }
345
+ ): Promise<void> {
346
+ const spinner = ora('Installing validation scripts...').start();
347
+
348
+ try {
349
+ const scriptsDir = path.join(this.claudeDir, 'scripts');
350
+ await fs.mkdir(scriptsDir, { recursive: true });
351
+
352
+ const scripts = this.generateValidationScripts();
353
+
354
+ for (const [scriptName, scriptContent] of Object.entries(scripts)) {
355
+ const scriptPath = path.join(scriptsDir, scriptName);
356
+
357
+ if (existsSync(scriptPath) && !options.overwrite) {
358
+ result.skipped.push(`scripts/${scriptName}`);
359
+ continue;
360
+ }
361
+
362
+ if (options.dryRun) {
363
+ result.installed.push(`scripts/${scriptName} (dry-run)`);
364
+ continue;
365
+ }
366
+
367
+ await fs.writeFile(scriptPath, scriptContent);
368
+ await fs.chmod(scriptPath, 0o755); // Make executable
369
+ result.installed.push(`scripts/${scriptName}`);
370
+ }
371
+
372
+ spinner.succeed(`Validation scripts installed (${Object.keys(scripts).length} scripts)`);
373
+ logger.info('Validation scripts installed', { count: Object.keys(scripts).length });
374
+ } catch (error) {
375
+ spinner.fail('Failed to install validation scripts');
376
+ result.errors.push({
377
+ file: 'validation-scripts',
378
+ error: error instanceof Error ? error.message : String(error)
379
+ });
380
+ logger.error('Validation scripts installation failed', error);
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Create directory structure
386
+ */
387
+ private async createDirectoryStructure(): Promise<void> {
388
+ const dirs = [
389
+ this.claudeDir,
390
+ path.join(this.claudeDir, 'hooks'),
391
+ path.join(this.claudeDir, 'agents'),
392
+ path.join(this.claudeDir, 'workflows'),
393
+ path.join(this.claudeDir, 'scripts'),
394
+ path.join(this.claudeDir, 'templates'),
395
+ ];
396
+
397
+ for (const dir of dirs) {
398
+ await fs.mkdir(dir, { recursive: true });
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Get existing config files for backup
404
+ */
405
+ private async getExistingConfigFiles(): Promise<string[]> {
406
+ const files: string[] = [];
407
+ const checkFiles = [
408
+ path.join(this.claudeDir, 'CLAUDE.md'),
409
+ path.join(this.claudeDir, 'conventions.json'),
410
+ ];
411
+
412
+ for (const file of checkFiles) {
413
+ if (existsSync(file)) {
414
+ files.push(file);
415
+ }
416
+ }
417
+
418
+ return files;
419
+ }
420
+
421
+ /**
422
+ * Generate hooks configuration files
423
+ */
424
+ private generateHooksConfig(): Record<string, string> {
425
+ return {
426
+ 'pre-commit': `#!/bin/bash
427
+ # Claude Code pre-commit hook
428
+ # Auto-generated by Wundr computer-setup
429
+
430
+ echo "šŸ” Running pre-commit checks..."
431
+
432
+ # Run linting
433
+ if command -v npm &> /dev/null; then
434
+ npm run lint --if-present || true
435
+ fi
436
+
437
+ # Run type checking
438
+ if command -v npm &> /dev/null; then
439
+ npm run typecheck --if-present || true
440
+ fi
441
+
442
+ echo "āœ… Pre-commit checks completed"
443
+ `,
444
+ 'post-checkout': `#!/bin/bash
445
+ # Claude Code post-checkout hook
446
+ # Auto-generated by Wundr computer-setup
447
+
448
+ echo "šŸ”„ Post-checkout: Installing dependencies..."
449
+
450
+ # Install dependencies if package.json changed
451
+ if command -v npm &> /dev/null; then
452
+ npm install --if-present || true
453
+ fi
454
+
455
+ echo "āœ… Post-checkout completed"
456
+ `,
457
+ };
458
+ }
459
+
460
+ /**
461
+ * Generate conventions configuration
462
+ */
463
+ private generateConventions(): any {
464
+ return {
465
+ fileNaming: {
466
+ components: 'PascalCase',
467
+ utilities: 'camelCase',
468
+ constants: 'UPPER_SNAKE_CASE',
469
+ types: 'PascalCase',
470
+ },
471
+ codeStyle: {
472
+ indentation: 2,
473
+ quotes: 'single',
474
+ semicolons: true,
475
+ trailingComma: 'es5',
476
+ },
477
+ imports: {
478
+ order: ['external', 'internal', 'parent', 'sibling', 'index'],
479
+ grouping: true,
480
+ },
481
+ testing: {
482
+ framework: 'jest',
483
+ coverage: {
484
+ statements: 80,
485
+ branches: 80,
486
+ functions: 80,
487
+ lines: 80,
488
+ },
489
+ },
490
+ git: {
491
+ commitMessage: 'conventional-commits',
492
+ branchNaming: 'feature/*, fix/*, chore/*',
493
+ },
494
+ };
495
+ }
496
+
497
+ /**
498
+ * Generate agent templates
499
+ */
500
+ private generateAgentTemplates(): Record<string, any> {
501
+ return {
502
+ 'backend-developer': {
503
+ name: 'Backend Developer',
504
+ role: 'backend-dev',
505
+ responsibilities: [
506
+ 'Design RESTful and GraphQL APIs',
507
+ 'Implement database models and queries',
508
+ 'Create authentication and authorization',
509
+ 'Write comprehensive API documentation',
510
+ ],
511
+ tools: ['node', 'typescript', 'postgresql', 'redis'],
512
+ patterns: [
513
+ 'Controller-Service-Repository',
514
+ 'DTO pattern',
515
+ 'Middleware pattern',
516
+ ],
517
+ },
518
+ 'frontend-developer': {
519
+ name: 'Frontend Developer',
520
+ role: 'frontend-dev',
521
+ responsibilities: [
522
+ 'Build responsive user interfaces',
523
+ 'Implement state management',
524
+ 'Create reusable components',
525
+ 'Optimize performance',
526
+ ],
527
+ tools: ['react', 'typescript', 'tailwind', 'vite'],
528
+ patterns: ['Component composition', 'Custom hooks', 'Context API'],
529
+ },
530
+ 'fullstack-developer': {
531
+ name: 'Fullstack Developer',
532
+ role: 'fullstack-dev',
533
+ responsibilities: [
534
+ 'Develop end-to-end features',
535
+ 'Integrate frontend and backend',
536
+ 'Manage database schemas',
537
+ 'Deploy applications',
538
+ ],
539
+ tools: ['node', 'react', 'typescript', 'docker'],
540
+ patterns: ['Full-stack architecture', 'API integration', 'CI/CD'],
541
+ },
542
+ };
543
+ }
544
+
545
+ /**
546
+ * Generate git-worktree workflows
547
+ */
548
+ private generateGitWorktreeWorkflows(): Record<string, any> {
549
+ return {
550
+ 'feature-development': {
551
+ name: 'Feature Development Workflow',
552
+ description: 'Workflow for developing new features in isolation',
553
+ steps: [
554
+ {
555
+ name: 'Create worktree',
556
+ command: 'git worktree add ../feature-name feature/name',
557
+ },
558
+ {
559
+ name: 'Setup environment',
560
+ command: 'cd ../feature-name && npm install',
561
+ },
562
+ {
563
+ name: 'Run tests',
564
+ command: 'npm test',
565
+ },
566
+ {
567
+ name: 'Commit changes',
568
+ command: 'git add . && git commit -m "feat: description"',
569
+ },
570
+ ],
571
+ },
572
+ 'bug-fix': {
573
+ name: 'Bug Fix Workflow',
574
+ description: 'Workflow for fixing bugs without affecting main development',
575
+ steps: [
576
+ {
577
+ name: 'Create worktree',
578
+ command: 'git worktree add ../fix-bug fix/bug-name',
579
+ },
580
+ {
581
+ name: 'Reproduce bug',
582
+ command: 'npm test -- bug.test.ts',
583
+ },
584
+ {
585
+ name: 'Fix and verify',
586
+ command: 'npm test',
587
+ },
588
+ {
589
+ name: 'Commit fix',
590
+ command: 'git add . && git commit -m "fix: description"',
591
+ },
592
+ ],
593
+ },
594
+ };
595
+ }
596
+
597
+ /**
598
+ * Generate validation scripts
599
+ */
600
+ private generateValidationScripts(): Record<string, string> {
601
+ return {
602
+ 'validate-setup.sh': `#!/bin/bash
603
+ # Validate Claude Code setup
604
+ # Auto-generated by Wundr computer-setup
605
+
606
+ echo "šŸ” Validating Claude Code setup..."
607
+
608
+ # Check for required files
609
+ FILES=(
610
+ "$HOME/.claude/CLAUDE.md"
611
+ "$HOME/.claude/conventions.json"
612
+ )
613
+
614
+ MISSING=0
615
+ for file in "\${FILES[@]}"; do
616
+ if [ ! -f "$file" ]; then
617
+ echo "āŒ Missing: $file"
618
+ MISSING=$((MISSING + 1))
619
+ else
620
+ echo "āœ… Found: $file"
621
+ fi
622
+ done
623
+
624
+ # Check for required directories
625
+ DIRS=(
626
+ "$HOME/.claude/hooks"
627
+ "$HOME/.claude/agents"
628
+ "$HOME/.claude/workflows"
629
+ )
630
+
631
+ for dir in "\${DIRS[@]}"; do
632
+ if [ ! -d "$dir" ]; then
633
+ echo "āŒ Missing directory: $dir"
634
+ MISSING=$((MISSING + 1))
635
+ else
636
+ echo "āœ… Found directory: $dir"
637
+ fi
638
+ done
639
+
640
+ if [ $MISSING -eq 0 ]; then
641
+ echo "āœ… All validations passed!"
642
+ exit 0
643
+ else
644
+ echo "āŒ $MISSING validation(s) failed"
645
+ exit 1
646
+ fi
647
+ `,
648
+ 'check-config.sh': `#!/bin/bash
649
+ # Check Claude Code configuration
650
+ # Auto-generated by Wundr computer-setup
651
+
652
+ echo "šŸ”§ Checking Claude Code configuration..."
653
+
654
+ # Check Claude CLI
655
+ if command -v claude &> /dev/null; then
656
+ echo "āœ… Claude CLI: $(claude --version)"
657
+ else
658
+ echo "āš ļø Claude CLI not found"
659
+ fi
660
+
661
+ # Check Node.js
662
+ if command -v node &> /dev/null; then
663
+ echo "āœ… Node.js: $(node --version)"
664
+ else
665
+ echo "āŒ Node.js not found"
666
+ fi
667
+
668
+ # Check Git
669
+ if command -v git &> /dev/null; then
670
+ echo "āœ… Git: $(git --version)"
671
+ else
672
+ echo "āŒ Git not found"
673
+ fi
674
+
675
+ echo "āœ… Configuration check complete"
676
+ `,
677
+ };
678
+ }
679
+
680
+ /**
681
+ * Display installation summary
682
+ */
683
+ private displayInstallSummary(result: InstallResult, dryRun: boolean): void {
684
+ console.log(chalk.cyan('\nšŸ“Š Installation Summary\n'));
685
+
686
+ if (dryRun) {
687
+ console.log(chalk.yellow('šŸ” DRY RUN MODE - No files were modified\n'));
688
+ }
689
+
690
+ if (result.backupId) {
691
+ console.log(chalk.gray(`Backup ID: ${result.backupId}\n`));
692
+ }
693
+
694
+ if (result.installed.length > 0) {
695
+ console.log(chalk.green(`āœ… Installed (${result.installed.length}):`));
696
+ result.installed.forEach(file => {
697
+ console.log(chalk.white(` • ${file}`));
698
+ });
699
+ console.log();
700
+ }
701
+
702
+ if (result.skipped.length > 0) {
703
+ console.log(chalk.yellow(`ā­ļø Skipped (${result.skipped.length}):`));
704
+ result.skipped.forEach(file => {
705
+ console.log(chalk.gray(` • ${file}`));
706
+ });
707
+ console.log();
708
+ }
709
+
710
+ if (result.errors.length > 0) {
711
+ console.log(chalk.red(`āŒ Errors (${result.errors.length}):`));
712
+ result.errors.forEach(error => {
713
+ console.log(chalk.red(` • ${error.file}: ${error.error}`));
714
+ });
715
+ console.log();
716
+ }
717
+
718
+ if (result.success) {
719
+ console.log(chalk.green('āœ… Installation completed successfully!\n'));
720
+ console.log(chalk.cyan('Next steps:'));
721
+ console.log(chalk.white(' 1. Review installed configurations'));
722
+ console.log(chalk.white(' 2. Run validation: ~/.claude/scripts/validate-setup.sh'));
723
+ console.log(chalk.white(' 3. Customize agent templates as needed'));
724
+ } else {
725
+ console.log(chalk.red('āŒ Installation completed with errors\n'));
726
+ if (result.backupId) {
727
+ console.log(chalk.cyan('To rollback:'));
728
+ console.log(chalk.white(` wundr computer-setup rollback --backup ${result.backupId}`));
729
+ }
730
+ }
731
+ }
732
+ }