@wundr.io/cli 1.0.0 → 1.0.2-dev.20260530174250.ef0ec927

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