@wundr.io/cli 1.0.0 → 1.0.3

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 (224) hide show
  1. package/README.md +696 -280
  2. package/dist/ai/ai-service.d.ts +2 -2
  3. package/dist/ai/ai-service.d.ts.map +1 -1
  4. package/dist/ai/ai-service.js +1 -1
  5. package/dist/ai/ai-service.js.map +1 -1
  6. package/dist/ai/claude-client.d.ts.map +1 -1
  7. package/dist/ai/claude-client.js +2 -1
  8. package/dist/ai/claude-client.js.map +1 -1
  9. package/dist/ai/conversation-manager.d.ts +2 -2
  10. package/dist/ai/conversation-manager.d.ts.map +1 -1
  11. package/dist/ai/conversation-manager.js +5 -3
  12. package/dist/ai/conversation-manager.js.map +1 -1
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +32 -13
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/ai.d.ts +3 -3
  17. package/dist/commands/ai.d.ts.map +1 -1
  18. package/dist/commands/ai.js +2 -2
  19. package/dist/commands/ai.js.map +1 -1
  20. package/dist/commands/alignment.d.ts +78 -0
  21. package/dist/commands/alignment.d.ts.map +1 -0
  22. package/dist/commands/alignment.js +817 -0
  23. package/dist/commands/alignment.js.map +1 -0
  24. package/dist/commands/analyze-optimized.d.ts.map +1 -1
  25. package/dist/commands/analyze-optimized.js +9 -6
  26. package/dist/commands/analyze-optimized.js.map +1 -1
  27. package/dist/commands/analyze.d.ts +3 -3
  28. package/dist/commands/analyze.d.ts.map +1 -1
  29. package/dist/commands/analyze.js +2 -2
  30. package/dist/commands/analyze.js.map +1 -1
  31. package/dist/commands/batch.d.ts +3 -3
  32. package/dist/commands/batch.d.ts.map +1 -1
  33. package/dist/commands/batch.js +7 -7
  34. package/dist/commands/batch.js.map +1 -1
  35. package/dist/commands/chat.d.ts +3 -3
  36. package/dist/commands/chat.d.ts.map +1 -1
  37. package/dist/commands/chat.js +3 -3
  38. package/dist/commands/chat.js.map +1 -1
  39. package/dist/commands/claude-init.d.ts +1 -1
  40. package/dist/commands/claude-init.d.ts.map +1 -1
  41. package/dist/commands/claude-init.js +11 -7
  42. package/dist/commands/claude-init.js.map +1 -1
  43. package/dist/commands/claude-setup.d.ts +88 -1
  44. package/dist/commands/claude-setup.d.ts.map +1 -1
  45. package/dist/commands/claude-setup.js +549 -46
  46. package/dist/commands/claude-setup.js.map +1 -1
  47. package/dist/commands/computer-setup-commands.d.ts +17 -3
  48. package/dist/commands/computer-setup-commands.d.ts.map +1 -1
  49. package/dist/commands/computer-setup-commands.js +145 -3
  50. package/dist/commands/computer-setup-commands.js.map +1 -1
  51. package/dist/commands/computer-setup.d.ts.map +1 -1
  52. package/dist/commands/computer-setup.js +372 -4
  53. package/dist/commands/computer-setup.js.map +1 -1
  54. package/dist/commands/create-command.d.ts.map +1 -1
  55. package/dist/commands/create-command.js +3 -3
  56. package/dist/commands/create-command.js.map +1 -1
  57. package/dist/commands/create.d.ts +3 -3
  58. package/dist/commands/create.d.ts.map +1 -1
  59. package/dist/commands/create.js +3 -3
  60. package/dist/commands/create.js.map +1 -1
  61. package/dist/commands/dashboard.d.ts +3 -3
  62. package/dist/commands/dashboard.d.ts.map +1 -1
  63. package/dist/commands/dashboard.js +4 -3
  64. package/dist/commands/dashboard.js.map +1 -1
  65. package/dist/commands/govern.d.ts +3 -3
  66. package/dist/commands/govern.d.ts.map +1 -1
  67. package/dist/commands/govern.js +4 -3
  68. package/dist/commands/govern.js.map +1 -1
  69. package/dist/commands/governance.d.ts +17 -0
  70. package/dist/commands/governance.d.ts.map +1 -0
  71. package/dist/commands/governance.js +703 -0
  72. package/dist/commands/governance.js.map +1 -0
  73. package/dist/commands/guardian.d.ts +20 -0
  74. package/dist/commands/guardian.d.ts.map +1 -0
  75. package/dist/commands/guardian.js +597 -0
  76. package/dist/commands/guardian.js.map +1 -0
  77. package/dist/commands/init.d.ts +7 -3
  78. package/dist/commands/init.d.ts.map +1 -1
  79. package/dist/commands/init.js +71 -5
  80. package/dist/commands/init.js.map +1 -1
  81. package/dist/commands/performance-optimizer.d.ts +2 -2
  82. package/dist/commands/performance-optimizer.d.ts.map +1 -1
  83. package/dist/commands/performance-optimizer.js +8 -7
  84. package/dist/commands/performance-optimizer.js.map +1 -1
  85. package/dist/commands/plugins.d.ts +3 -3
  86. package/dist/commands/plugins.d.ts.map +1 -1
  87. package/dist/commands/plugins.js +2 -2
  88. package/dist/commands/plugins.js.map +1 -1
  89. package/dist/commands/rag.d.ts +7 -0
  90. package/dist/commands/rag.d.ts.map +1 -0
  91. package/dist/commands/rag.js +748 -0
  92. package/dist/commands/rag.js.map +1 -0
  93. package/dist/commands/session.d.ts +41 -0
  94. package/dist/commands/session.d.ts.map +1 -0
  95. package/dist/commands/session.js +441 -0
  96. package/dist/commands/session.js.map +1 -0
  97. package/dist/commands/setup.d.ts +3 -3
  98. package/dist/commands/setup.d.ts.map +1 -1
  99. package/dist/commands/setup.js +1 -3
  100. package/dist/commands/setup.js.map +1 -1
  101. package/dist/commands/test-init.d.ts.map +1 -1
  102. package/dist/commands/test-init.js +2 -2
  103. package/dist/commands/test-init.js.map +1 -1
  104. package/dist/commands/test.d.ts.map +1 -1
  105. package/dist/commands/test.js +2 -2
  106. package/dist/commands/test.js.map +1 -1
  107. package/dist/commands/vp.d.ts +7 -0
  108. package/dist/commands/vp.d.ts.map +1 -0
  109. package/dist/commands/vp.js +571 -0
  110. package/dist/commands/vp.js.map +1 -0
  111. package/dist/commands/watch.d.ts +3 -3
  112. package/dist/commands/watch.d.ts.map +1 -1
  113. package/dist/commands/watch.js +10 -7
  114. package/dist/commands/watch.js.map +1 -1
  115. package/dist/commands/worktree.d.ts +63 -0
  116. package/dist/commands/worktree.d.ts.map +1 -0
  117. package/dist/commands/worktree.js +774 -0
  118. package/dist/commands/worktree.js.map +1 -0
  119. package/dist/context/context-manager.d.ts +1 -1
  120. package/dist/context/context-manager.d.ts.map +1 -1
  121. package/dist/context/context-manager.js +1 -1
  122. package/dist/context/context-manager.js.map +1 -1
  123. package/dist/context/session-manager.d.ts +2 -2
  124. package/dist/context/session-manager.d.ts.map +1 -1
  125. package/dist/context/session-manager.js +9 -5
  126. package/dist/context/session-manager.js.map +1 -1
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +1 -1
  129. package/dist/index.js.map +1 -1
  130. package/dist/interactive/interactive-mode.d.ts +2 -2
  131. package/dist/interactive/interactive-mode.d.ts.map +1 -1
  132. package/dist/interactive/interactive-mode.js +6 -4
  133. package/dist/interactive/interactive-mode.js.map +1 -1
  134. package/dist/nlp/command-mapper.d.ts +1 -1
  135. package/dist/nlp/command-mapper.d.ts.map +1 -1
  136. package/dist/nlp/command-mapper.js +3 -2
  137. package/dist/nlp/command-mapper.js.map +1 -1
  138. package/dist/nlp/command-parser.d.ts +1 -1
  139. package/dist/nlp/command-parser.d.ts.map +1 -1
  140. package/dist/nlp/command-parser.js +2 -1
  141. package/dist/nlp/command-parser.js.map +1 -1
  142. package/dist/nlp/intent-parser.d.ts +1 -1
  143. package/dist/nlp/intent-parser.d.ts.map +1 -1
  144. package/dist/nlp/intent-parser.js +14 -9
  145. package/dist/nlp/intent-parser.js.map +1 -1
  146. package/dist/plugins/plugin-manager.d.ts +2 -2
  147. package/dist/plugins/plugin-manager.d.ts.map +1 -1
  148. package/dist/plugins/plugin-manager.js +3 -3
  149. package/dist/plugins/plugin-manager.js.map +1 -1
  150. package/dist/types/index.d.ts +1 -1
  151. package/dist/types/index.d.ts.map +1 -1
  152. package/dist/utils/backup-rollback-manager.d.ts +72 -0
  153. package/dist/utils/backup-rollback-manager.d.ts.map +1 -0
  154. package/dist/utils/backup-rollback-manager.js +289 -0
  155. package/dist/utils/backup-rollback-manager.js.map +1 -0
  156. package/dist/utils/claude-config-installer.d.ts +94 -0
  157. package/dist/utils/claude-config-installer.d.ts.map +1 -0
  158. package/dist/utils/claude-config-installer.js +628 -0
  159. package/dist/utils/claude-config-installer.js.map +1 -0
  160. package/dist/utils/config-manager.d.ts +1 -1
  161. package/dist/utils/config-manager.d.ts.map +1 -1
  162. package/dist/utils/config-manager.js +5 -5
  163. package/dist/utils/config-manager.js.map +1 -1
  164. package/dist/utils/error-handler.d.ts +1 -1
  165. package/dist/utils/error-handler.d.ts.map +1 -1
  166. package/dist/utils/error-handler.js.map +1 -1
  167. package/dist/utils/logger.d.ts +1 -1
  168. package/dist/utils/logger.d.ts.map +1 -1
  169. package/dist/utils/logger.js +22 -11
  170. package/dist/utils/logger.js.map +1 -1
  171. package/package.json +26 -7
  172. package/src/ai/ai-service.ts +22 -19
  173. package/src/ai/claude-client.ts +20 -16
  174. package/src/ai/conversation-manager.ts +37 -30
  175. package/src/cli.ts +42 -13
  176. package/src/commands/ai.ts +59 -57
  177. package/src/commands/alignment.ts +1212 -0
  178. package/src/commands/analyze-optimized.ts +70 -62
  179. package/src/commands/analyze.ts +22 -20
  180. package/src/commands/batch.ts +41 -38
  181. package/src/commands/chat.ts +37 -34
  182. package/src/commands/claude-init.ts +38 -30
  183. package/src/commands/claude-setup.ts +692 -97
  184. package/src/commands/computer-setup-commands.ts +203 -37
  185. package/src/commands/computer-setup.ts +474 -4
  186. package/src/commands/create-command.ts +7 -7
  187. package/src/commands/create.ts +36 -33
  188. package/src/commands/dashboard.ts +33 -28
  189. package/src/commands/govern.ts +34 -29
  190. package/src/commands/governance.ts +1005 -0
  191. package/src/commands/guardian.ts +887 -0
  192. package/src/commands/init.ts +112 -22
  193. package/src/commands/performance-optimizer.ts +48 -42
  194. package/src/commands/plugins.ts +35 -32
  195. package/src/commands/project-update.ts +1053 -0
  196. package/src/commands/rag.ts +904 -0
  197. package/src/commands/session.ts +631 -0
  198. package/src/commands/setup.ts +35 -31
  199. package/src/commands/test-init.ts +6 -5
  200. package/src/commands/test.ts +7 -6
  201. package/src/commands/vp.ts +762 -0
  202. package/src/commands/watch.ts +44 -33
  203. package/src/commands/worktree.ts +1057 -0
  204. package/src/context/context-manager.ts +15 -12
  205. package/src/context/session-manager.ts +51 -40
  206. package/src/index.ts +7 -6
  207. package/src/interactive/interactive-mode.ts +25 -18
  208. package/src/lib/conflict-resolution.ts +28 -0
  209. package/src/lib/merge-strategy.ts +28 -0
  210. package/src/lib/safety-mechanisms.ts +47 -0
  211. package/src/lib/state-detection.ts +28 -0
  212. package/src/nlp/command-mapper.ts +35 -30
  213. package/src/nlp/command-parser.ts +20 -17
  214. package/src/nlp/intent-classifier.ts +7 -7
  215. package/src/nlp/intent-parser.ts +61 -49
  216. package/src/plugins/plugin-manager.ts +27 -23
  217. package/src/tests/computer-setup-integration.test.ts +439 -0
  218. package/src/types/index.ts +1 -1
  219. package/src/types/modules.d.ts +1 -0
  220. package/src/utils/backup-rollback-manager.ts +363 -0
  221. package/src/utils/claude-config-installer.ts +734 -0
  222. package/src/utils/config-manager.ts +12 -9
  223. package/src/utils/error-handler.ts +5 -3
  224. package/src/utils/logger.ts +35 -12
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Integration tests for computer-setup with Claude Code configuration
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
6
+ import * as fs from 'fs/promises';
7
+ import * as path from 'path';
8
+ import { existsSync } from 'fs';
9
+ import { BackupRollbackManager } from '../utils/backup-rollback-manager';
10
+ import { ClaudeConfigInstaller } from '../utils/claude-config-installer';
11
+
12
+ describe('Computer Setup Integration Tests', () => {
13
+ const testDir = path.join(__dirname, '.test-temp');
14
+ const backupDir = path.join(testDir, 'backups');
15
+ const claudeDir = path.join(testDir, '.claude');
16
+
17
+ beforeEach(async () => {
18
+ // Create test directories
19
+ await fs.mkdir(testDir, { recursive: true });
20
+ await fs.mkdir(backupDir, { recursive: true });
21
+ await fs.mkdir(claudeDir, { recursive: true });
22
+ });
23
+
24
+ afterEach(async () => {
25
+ // Clean up test directories
26
+ await fs.rm(testDir, { recursive: true, force: true });
27
+ });
28
+
29
+ describe('BackupRollbackManager', () => {
30
+ let backupManager: BackupRollbackManager;
31
+
32
+ beforeEach(async () => {
33
+ backupManager = new BackupRollbackManager(backupDir);
34
+ await backupManager.initialize();
35
+ });
36
+
37
+ it('should initialize backup directory', async () => {
38
+ expect(existsSync(backupDir)).toBe(true);
39
+ });
40
+
41
+ it('should create backup of files', async () => {
42
+ // Create test files
43
+ const testFile1 = path.join(testDir, 'test1.txt');
44
+ const testFile2 = path.join(testDir, 'test2.txt');
45
+ await fs.writeFile(testFile1, 'content1');
46
+ await fs.writeFile(testFile2, 'content2');
47
+
48
+ // Create backup
49
+ const metadata = await backupManager.createBackup(
50
+ [testFile1, testFile2],
51
+ 'Test backup'
52
+ );
53
+
54
+ expect(metadata.success).toBe(true);
55
+ expect(metadata.files).toHaveLength(2);
56
+ expect(metadata.backupId).toBeTruthy();
57
+
58
+ // Verify backup files exist
59
+ for (const file of metadata.files) {
60
+ expect(existsSync(file.backupPath)).toBe(true);
61
+ }
62
+ });
63
+
64
+ it('should list backups', async () => {
65
+ // Create test file and backup
66
+ const testFile = path.join(testDir, 'test.txt');
67
+ await fs.writeFile(testFile, 'content');
68
+
69
+ await backupManager.createBackup([testFile], 'Backup 1');
70
+ await backupManager.createBackup([testFile], 'Backup 2');
71
+
72
+ const backups = await backupManager.listBackups();
73
+ expect(backups.length).toBeGreaterThanOrEqual(2);
74
+ });
75
+
76
+ it('should restore files from backup', async () => {
77
+ // Create original file
78
+ const testFile = path.join(testDir, 'test.txt');
79
+ await fs.writeFile(testFile, 'original content');
80
+
81
+ // Create backup
82
+ const metadata = await backupManager.createBackup([testFile], 'Test backup');
83
+
84
+ // Modify file
85
+ await fs.writeFile(testFile, 'modified content');
86
+
87
+ // Restore from backup
88
+ const success = await backupManager.rollback({
89
+ backupId: metadata.backupId,
90
+ dryRun: false,
91
+ });
92
+
93
+ expect(success).toBe(true);
94
+
95
+ // Verify content restored
96
+ const content = await fs.readFile(testFile, 'utf-8');
97
+ expect(content).toBe('original content');
98
+ });
99
+
100
+ it('should verify backup integrity', async () => {
101
+ // Create test file and backup
102
+ const testFile = path.join(testDir, 'test.txt');
103
+ await fs.writeFile(testFile, 'content');
104
+
105
+ const metadata = await backupManager.createBackup([testFile], 'Test backup');
106
+
107
+ const isValid = await backupManager.verifyBackup(metadata.backupId);
108
+ expect(isValid).toBe(true);
109
+ });
110
+
111
+ it('should clean up old backups', async () => {
112
+ // Create multiple backups
113
+ const testFile = path.join(testDir, 'test.txt');
114
+ await fs.writeFile(testFile, 'content');
115
+
116
+ for (let i = 0; i < 10; i++) {
117
+ await backupManager.createBackup([testFile], `Backup ${i}`);
118
+ }
119
+
120
+ // Clean up, keeping only 5
121
+ await backupManager.cleanupOldBackups(5);
122
+
123
+ const backups = await backupManager.listBackups();
124
+ expect(backups.length).toBeLessThanOrEqual(5);
125
+ });
126
+
127
+ it('should handle dry-run rollback', async () => {
128
+ const testFile = path.join(testDir, 'test.txt');
129
+ await fs.writeFile(testFile, 'original');
130
+
131
+ const metadata = await backupManager.createBackup([testFile], 'Test');
132
+
133
+ await fs.writeFile(testFile, 'modified');
134
+
135
+ const success = await backupManager.rollback({
136
+ backupId: metadata.backupId,
137
+ dryRun: true,
138
+ });
139
+
140
+ expect(success).toBe(true);
141
+
142
+ // File should not be restored in dry-run
143
+ const content = await fs.readFile(testFile, 'utf-8');
144
+ expect(content).toBe('modified');
145
+ });
146
+ });
147
+
148
+ describe('ClaudeConfigInstaller', () => {
149
+ let installer: ClaudeConfigInstaller;
150
+
151
+ beforeEach(async () => {
152
+ installer = new ClaudeConfigInstaller({
153
+ claudeDir,
154
+ sourceDir: testDir,
155
+ });
156
+ await installer.initialize();
157
+
158
+ // Create mock CLAUDE.md
159
+ await fs.writeFile(
160
+ path.join(testDir, 'CLAUDE.md'),
161
+ '# Claude Configuration\nTest content'
162
+ );
163
+ });
164
+
165
+ it('should initialize directory structure', async () => {
166
+ expect(existsSync(claudeDir)).toBe(true);
167
+ expect(existsSync(path.join(claudeDir, 'hooks'))).toBe(true);
168
+ expect(existsSync(path.join(claudeDir, 'agents'))).toBe(true);
169
+ expect(existsSync(path.join(claudeDir, 'workflows'))).toBe(true);
170
+ expect(existsSync(path.join(claudeDir, 'scripts'))).toBe(true);
171
+ });
172
+
173
+ it('should install CLAUDE.md', async () => {
174
+ const result = await installer.install({
175
+ dryRun: false,
176
+ skipBackup: true,
177
+ });
178
+
179
+ expect(result.success).toBe(true);
180
+ expect(result.installed).toContain('CLAUDE.md');
181
+ expect(existsSync(path.join(claudeDir, 'CLAUDE.md'))).toBe(true);
182
+ });
183
+
184
+ it('should install hooks', async () => {
185
+ const result = await installer.install({
186
+ dryRun: false,
187
+ skipBackup: true,
188
+ });
189
+
190
+ expect(result.success).toBe(true);
191
+
192
+ const hooksDir = path.join(claudeDir, 'hooks');
193
+ expect(existsSync(path.join(hooksDir, 'pre-commit'))).toBe(true);
194
+ expect(existsSync(path.join(hooksDir, 'post-checkout'))).toBe(true);
195
+ });
196
+
197
+ it('should install conventions', async () => {
198
+ const result = await installer.install({
199
+ dryRun: false,
200
+ skipBackup: true,
201
+ });
202
+
203
+ expect(result.success).toBe(true);
204
+ expect(result.installed).toContain('conventions.json');
205
+
206
+ const conventionsPath = path.join(claudeDir, 'conventions.json');
207
+ expect(existsSync(conventionsPath)).toBe(true);
208
+
209
+ const conventions = JSON.parse(await fs.readFile(conventionsPath, 'utf-8'));
210
+ expect(conventions).toHaveProperty('fileNaming');
211
+ expect(conventions).toHaveProperty('codeStyle');
212
+ });
213
+
214
+ it('should install agent templates', async () => {
215
+ const result = await installer.install({
216
+ dryRun: false,
217
+ skipBackup: true,
218
+ });
219
+
220
+ expect(result.success).toBe(true);
221
+
222
+ const agentsDir = path.join(claudeDir, 'agents');
223
+ expect(existsSync(path.join(agentsDir, 'backend-developer.json'))).toBe(true);
224
+ expect(existsSync(path.join(agentsDir, 'frontend-developer.json'))).toBe(true);
225
+ expect(existsSync(path.join(agentsDir, 'fullstack-developer.json'))).toBe(true);
226
+ });
227
+
228
+ it('should install git-worktree workflows', async () => {
229
+ const result = await installer.install({
230
+ dryRun: false,
231
+ skipBackup: true,
232
+ });
233
+
234
+ expect(result.success).toBe(true);
235
+
236
+ const workflowsDir = path.join(claudeDir, 'workflows');
237
+ expect(
238
+ existsSync(path.join(workflowsDir, 'feature-development.json'))
239
+ ).toBe(true);
240
+ expect(existsSync(path.join(workflowsDir, 'bug-fix.json'))).toBe(true);
241
+ });
242
+
243
+ it('should install validation scripts', async () => {
244
+ const result = await installer.install({
245
+ dryRun: false,
246
+ skipBackup: true,
247
+ });
248
+
249
+ expect(result.success).toBe(true);
250
+
251
+ const scriptsDir = path.join(claudeDir, 'scripts');
252
+ expect(existsSync(path.join(scriptsDir, 'validate-setup.sh'))).toBe(true);
253
+ expect(existsSync(path.join(scriptsDir, 'check-config.sh'))).toBe(true);
254
+ });
255
+
256
+ it('should handle dry-run installation', async () => {
257
+ const result = await installer.install({
258
+ dryRun: true,
259
+ skipBackup: true,
260
+ });
261
+
262
+ expect(result.success).toBe(true);
263
+ expect(result.installed.every(f => f.includes('dry-run'))).toBe(true);
264
+
265
+ // Files should not exist in dry-run
266
+ expect(existsSync(path.join(claudeDir, 'CLAUDE.md'))).toBe(false);
267
+ });
268
+
269
+ it('should skip existing files without overwrite', async () => {
270
+ // Create existing file
271
+ await fs.writeFile(path.join(claudeDir, 'CLAUDE.md'), 'existing content');
272
+
273
+ const result = await installer.install({
274
+ dryRun: false,
275
+ skipBackup: true,
276
+ overwrite: false,
277
+ });
278
+
279
+ expect(result.skipped).toContain('CLAUDE.md');
280
+
281
+ // Content should remain unchanged
282
+ const content = await fs.readFile(path.join(claudeDir, 'CLAUDE.md'), 'utf-8');
283
+ expect(content).toBe('existing content');
284
+ });
285
+
286
+ it('should overwrite existing files with overwrite flag', async () => {
287
+ // Create existing file
288
+ await fs.writeFile(path.join(claudeDir, 'CLAUDE.md'), 'existing content');
289
+
290
+ const result = await installer.install({
291
+ dryRun: false,
292
+ skipBackup: true,
293
+ overwrite: true,
294
+ });
295
+
296
+ expect(result.installed).toContain('CLAUDE.md');
297
+
298
+ // Content should be updated
299
+ const content = await fs.readFile(path.join(claudeDir, 'CLAUDE.md'), 'utf-8');
300
+ expect(content).toContain('Test content');
301
+ });
302
+
303
+ it('should create backup before installation', async () => {
304
+ // Create existing configurations
305
+ await fs.writeFile(path.join(claudeDir, 'CLAUDE.md'), 'existing');
306
+ await fs.writeFile(
307
+ path.join(claudeDir, 'conventions.json'),
308
+ JSON.stringify({ test: true })
309
+ );
310
+
311
+ const result = await installer.install({
312
+ dryRun: false,
313
+ skipBackup: false,
314
+ overwrite: true,
315
+ });
316
+
317
+ expect(result.backupId).toBeTruthy();
318
+ });
319
+ });
320
+
321
+ describe('End-to-End Integration', () => {
322
+ it('should complete full installation workflow', async () => {
323
+ const backupManager = new BackupRollbackManager(backupDir);
324
+ const installer = new ClaudeConfigInstaller({
325
+ claudeDir,
326
+ sourceDir: testDir,
327
+ });
328
+
329
+ await backupManager.initialize();
330
+ await installer.initialize();
331
+
332
+ // Create mock source file
333
+ await fs.writeFile(
334
+ path.join(testDir, 'CLAUDE.md'),
335
+ '# Enhanced Claude Configuration'
336
+ );
337
+
338
+ // Install configurations
339
+ const installResult = await installer.install({
340
+ dryRun: false,
341
+ skipBackup: false,
342
+ });
343
+
344
+ expect(installResult.success).toBe(true);
345
+ expect(installResult.installed.length).toBeGreaterThan(0);
346
+
347
+ // Verify all components installed
348
+ expect(existsSync(path.join(claudeDir, 'CLAUDE.md'))).toBe(true);
349
+ expect(existsSync(path.join(claudeDir, 'conventions.json'))).toBe(true);
350
+ expect(existsSync(path.join(claudeDir, 'hooks', 'pre-commit'))).toBe(true);
351
+ expect(existsSync(path.join(claudeDir, 'agents', 'backend-developer.json'))).toBe(
352
+ true
353
+ );
354
+ expect(
355
+ existsSync(path.join(claudeDir, 'workflows', 'feature-development.json'))
356
+ ).toBe(true);
357
+ expect(existsSync(path.join(claudeDir, 'scripts', 'validate-setup.sh'))).toBe(
358
+ true
359
+ );
360
+ });
361
+
362
+ it('should support complete backup and rollback cycle', async () => {
363
+ const backupManager = new BackupRollbackManager(backupDir);
364
+ const installer = new ClaudeConfigInstaller({
365
+ claudeDir,
366
+ sourceDir: testDir,
367
+ });
368
+
369
+ await backupManager.initialize();
370
+ await installer.initialize();
371
+
372
+ // Create initial config
373
+ const initialConfig = path.join(claudeDir, 'CLAUDE.md');
374
+ await fs.writeFile(initialConfig, 'Initial configuration');
375
+
376
+ // Create backup
377
+ const backup = await backupManager.createBackup(
378
+ [initialConfig],
379
+ 'Pre-update backup'
380
+ );
381
+
382
+ // Update configuration
383
+ await fs.writeFile(initialConfig, 'Updated configuration');
384
+
385
+ // Rollback to original
386
+ const success = await backupManager.rollback({
387
+ backupId: backup.backupId,
388
+ dryRun: false,
389
+ });
390
+
391
+ expect(success).toBe(true);
392
+
393
+ // Verify rollback
394
+ const content = await fs.readFile(initialConfig, 'utf-8');
395
+ expect(content).toBe('Initial configuration');
396
+ });
397
+ });
398
+
399
+ describe('Error Handling', () => {
400
+ it('should handle missing source files gracefully', async () => {
401
+ const installer = new ClaudeConfigInstaller({
402
+ claudeDir,
403
+ sourceDir: testDir,
404
+ });
405
+
406
+ await installer.initialize();
407
+
408
+ // Don't create CLAUDE.md source
409
+ const result = await installer.install({
410
+ dryRun: false,
411
+ skipBackup: true,
412
+ });
413
+
414
+ // Should skip missing files
415
+ expect(result.skipped).toContain('CLAUDE.md');
416
+ });
417
+
418
+ it('should handle permission errors', async () => {
419
+ const installer = new ClaudeConfigInstaller({
420
+ claudeDir: '/root/unauthorized', // Likely no permission
421
+ sourceDir: testDir,
422
+ });
423
+
424
+ await expect(installer.initialize()).rejects.toThrow();
425
+ });
426
+
427
+ it('should handle corrupted backup metadata', async () => {
428
+ const backupManager = new BackupRollbackManager(backupDir);
429
+ await backupManager.initialize();
430
+
431
+ // Corrupt metadata file
432
+ const metadataPath = path.join(backupDir, 'metadata.json');
433
+ await fs.writeFile(metadataPath, 'invalid json {');
434
+
435
+ const backups = await backupManager.listBackups();
436
+ expect(backups).toEqual([]);
437
+ });
438
+ });
439
+ });
@@ -1,4 +1,4 @@
1
- import { Command } from 'commander';
1
+ import type { Command } from 'commander';
2
2
 
3
3
  /**
4
4
  * Core types for the Wundr CLI
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-function-type */
1
2
  // Type declarations for external modules
2
3
  declare module '@wundr/computer-setup' {
3
4
  export class ComputerSetupManager {