@wundr.io/cli 1.0.1 → 1.0.2-dev.20260530180455.e1307186

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 (69) hide show
  1. package/bin/wundr.js +13 -5
  2. package/package.json +30 -9
  3. package/src/ai/ai-service.ts +6 -4
  4. package/src/ai/claude-client.ts +6 -2
  5. package/src/ai/conversation-manager.ts +12 -5
  6. package/src/cli.ts +42 -13
  7. package/src/commands/ai.ts +340 -64
  8. package/src/commands/alignment.ts +1212 -0
  9. package/src/commands/analyze-optimized.ts +371 -33
  10. package/src/commands/analyze.ts +8 -6
  11. package/src/commands/batch.ts +166 -26
  12. package/src/commands/chat.ts +20 -10
  13. package/src/commands/claude-init.ts +31 -27
  14. package/src/commands/claude-setup.ts +761 -81
  15. package/src/commands/computer-setup.ts +524 -12
  16. package/src/commands/create-command.ts +3 -3
  17. package/src/commands/create.ts +9 -6
  18. package/src/commands/dashboard.ts +11 -6
  19. package/src/commands/govern.ts +11 -6
  20. package/src/commands/governance.ts +1005 -0
  21. package/src/commands/guardian.ts +887 -0
  22. package/src/commands/init.ts +104 -11
  23. package/src/commands/orchestrator.ts +789 -0
  24. package/src/commands/performance-optimizer.ts +15 -10
  25. package/src/commands/plugins.ts +8 -5
  26. package/src/commands/project-update.ts +1156 -0
  27. package/src/commands/rag.ts +1011 -0
  28. package/src/commands/session.ts +631 -0
  29. package/src/commands/setup.ts +42 -344
  30. package/src/commands/test-init.ts +3 -2
  31. package/src/commands/test.ts +3 -2
  32. package/src/commands/watch.ts +21 -11
  33. package/src/commands/worktree.ts +1057 -0
  34. package/src/context/context-manager.ts +5 -2
  35. package/src/context/session-manager.ts +18 -7
  36. package/src/framework/command-interface.ts +520 -0
  37. package/src/framework/command-registry.ts +942 -0
  38. package/src/framework/completion-exporter.ts +383 -0
  39. package/src/framework/debug-logger.ts +519 -0
  40. package/src/framework/error-handler.ts +867 -0
  41. package/src/framework/help-generator.ts +540 -0
  42. package/src/framework/index.ts +169 -0
  43. package/src/framework/interactive-repl.ts +703 -0
  44. package/src/framework/output-formatter.ts +834 -0
  45. package/src/framework/progress-manager.ts +539 -0
  46. package/src/index.ts +3 -2
  47. package/src/interactive/interactive-mode.ts +14 -7
  48. package/src/lib/conflict-resolution.ts +818 -0
  49. package/src/lib/merge-strategy.ts +550 -0
  50. package/src/lib/safety-mechanisms.ts +451 -0
  51. package/src/lib/state-detection.ts +1030 -0
  52. package/src/nlp/command-mapper.ts +8 -3
  53. package/src/nlp/command-parser.ts +5 -2
  54. package/src/nlp/intent-parser.ts +23 -9
  55. package/src/plugins/plugin-manager.ts +50 -24
  56. package/src/tests/computer-setup-integration.test.ts +46 -15
  57. package/src/types/index.ts +1 -1
  58. package/src/types/modules.d.ts +425 -1
  59. package/src/utils/backup-rollback-manager.ts +19 -14
  60. package/src/utils/claude-config-installer.ts +119 -28
  61. package/src/utils/config-manager.ts +9 -6
  62. package/src/utils/error-handler.ts +3 -1
  63. package/src/utils/logger.ts +35 -12
  64. package/templates/batch/ci-cd.yaml +7 -7
  65. package/test-suites/api/health.spec.ts +20 -23
  66. package/test-suites/helpers/test-config.ts +14 -13
  67. package/test-suites/ui/accessibility.spec.ts +27 -22
  68. package/test-suites/ui/smoke.spec.ts +26 -21
  69. package/src/commands/computer-setup-commands.ts +0 -869
@@ -1,7 +1,10 @@
1
+ import { spawn } from 'child_process';
1
2
  import { EventEmitter } from 'events';
2
- import { spawn, ChildProcess } from 'child_process';
3
+
3
4
  import { logger } from '../utils/logger';
4
- import { IntentResult } from './intent-parser';
5
+
6
+ import type { IntentResult } from './intent-parser';
7
+ import type { ChildProcess } from 'child_process';
5
8
 
6
9
  /**
7
10
  * Command execution result
@@ -807,7 +810,9 @@ export class CommandMapper extends EventEmitter {
807
810
  case 'directory_exists':
808
811
  const fsDir = await import('fs-extra');
809
812
  const dirPath = parameters[rule.rule as string];
810
- if (!dirPath) return false;
813
+ if (!dirPath) {
814
+ return false;
815
+ }
811
816
  const stats = await fsDir.stat(dirPath).catch(() => null);
812
817
  return stats ? stats.isDirectory() : false;
813
818
 
@@ -1,5 +1,6 @@
1
1
  import { logger } from '../utils/logger';
2
- import { AIService, ConversationContext } from '../ai/ai-service';
2
+
3
+ import type { AIService, ConversationContext } from '../ai/ai-service';
3
4
 
4
5
  /**
5
6
  * Natural language command parsing result
@@ -141,7 +142,9 @@ export class CommandParser {
141
142
 
142
143
  for (let i = 0; i < steps.length; i++) {
143
144
  const step = steps[i];
144
- if (!step) continue;
145
+ if (!step) {
146
+ continue;
147
+ }
145
148
 
146
149
  const stepResult = await this.parseCommand(step, context);
147
150
 
@@ -1,7 +1,9 @@
1
1
  import { EventEmitter } from 'events';
2
- import { ClaudeClient, ClaudeMessage } from '../ai/claude-client';
2
+
3
3
  import { logger } from '../utils/logger';
4
4
 
5
+ import type { ClaudeClient, ClaudeMessage } from '../ai/claude-client';
6
+
5
7
  /**
6
8
  * Intent classification result
7
9
  */
@@ -559,7 +561,9 @@ Extract parameters from the user input and respond with JSON only:
559
561
  };
560
562
 
561
563
  for (const [intent, pattern] of this.commandPatterns) {
562
- if (!availableCommands.includes(intent)) continue;
564
+ if (!availableCommands.includes(intent)) {
565
+ continue;
566
+ }
563
567
 
564
568
  const confidence = this.calculatePatternScore(input, pattern);
565
569
 
@@ -592,7 +596,9 @@ Extract parameters from the user input and respond with JSON only:
592
596
 
593
597
  let matchCount = 0;
594
598
  for (const word of patternWords) {
595
- if (word.startsWith('{') && word.endsWith('}')) continue; // Skip parameters
599
+ if (word.startsWith('{') && word.endsWith('}')) {
600
+ continue;
601
+ } // Skip parameters
596
602
  if (inputWords.includes(word)) {
597
603
  matchCount++;
598
604
  }
@@ -752,12 +758,13 @@ Analyze and respond with JSON only:
752
758
 
753
759
  if (patternResult.intent === aiResult.intent) {
754
760
  finalResult.confidence = Math.min(0.98, aiResult.confidence + 0.1);
755
- finalResult.reasoning += ` (confirmed by pattern matching)`;
761
+ finalResult.reasoning += ' (confirmed by pattern matching)';
756
762
  } else if (patternResult.confidence > 0.8) {
757
763
  // High-confidence pattern match might override AI
758
764
  if (patternResult.confidence > aiResult.confidence) {
759
765
  finalResult = patternResult;
760
- finalResult.reasoning += ` (overridden by high-confidence pattern match)`;
766
+ finalResult.reasoning +=
767
+ ' (overridden by high-confidence pattern match)';
761
768
  }
762
769
  }
763
770
 
@@ -784,7 +791,8 @@ Analyze and respond with JSON only:
784
791
  // Add safety warnings for destructive commands
785
792
  const commandPattern = this.commandPatterns.get(result.intent);
786
793
  if (commandPattern?.destructive) {
787
- result.clarification = `This is a destructive operation. Are you sure you want to proceed?`;
794
+ result.clarification =
795
+ 'This is a destructive operation. Are you sure you want to proceed?';
788
796
  }
789
797
 
790
798
  // Enrich with context-aware suggestions
@@ -922,7 +930,9 @@ Analyze and respond with JSON only:
922
930
 
923
931
  for (const command of availableCommands) {
924
932
  const pattern = this.commandPatterns.get(command);
925
- if (!pattern) continue;
933
+ if (!pattern) {
934
+ continue;
935
+ }
926
936
 
927
937
  // Check if partial input matches command or examples
928
938
  const confidence = Math.max(
@@ -1063,8 +1073,12 @@ Provide ${limit} suggestions in JSON format:
1063
1073
  negativeWords.includes(word)
1064
1074
  ).length;
1065
1075
 
1066
- if (positiveCount > negativeCount) return 'positive';
1067
- if (negativeCount > positiveCount) return 'negative';
1076
+ if (positiveCount > negativeCount) {
1077
+ return 'positive';
1078
+ }
1079
+ if (negativeCount > positiveCount) {
1080
+ return 'negative';
1081
+ }
1068
1082
  return 'neutral';
1069
1083
  }
1070
1084
 
@@ -1,11 +1,19 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
1
  import { spawn, type ChildProcess } from 'child_process';
2
+ import path from 'path';
3
+
4
4
  import chalk from 'chalk';
5
- import { ConfigManager } from '../utils/config-manager';
6
- import { logger } from '../utils/logger';
5
+ import fs from 'fs-extra';
6
+
7
7
  import { errorHandler } from '../utils/error-handler';
8
- import { Plugin, PluginContext, PluginCommand, PluginHook } from '../types';
8
+ import { logger } from '../utils/logger';
9
+
10
+ import type {
11
+ Plugin,
12
+ PluginContext,
13
+ PluginCommand,
14
+ PluginHook,
15
+ } from '../types';
16
+ import type { ConfigManager } from '../utils/config-manager';
9
17
 
10
18
  /**
11
19
  * Plugin management system for CLI extensibility
@@ -306,28 +314,46 @@ export class PluginManager {
306
314
  }
307
315
 
308
316
  /**
309
- * Get available plugins from registry
317
+ * Get available plugins by scanning the plugins directory on the filesystem.
318
+ * Returns an empty array if the directory does not exist or contains no valid plugins.
310
319
  */
311
320
  async getAvailablePlugins(): Promise<any[]> {
312
321
  try {
313
- // This would query a plugin registry
314
- // For now, return mock data
315
- return [
316
- {
317
- name: '@wundr/plugin-git',
318
- version: '1.0.0',
319
- description: 'Git integration plugin',
320
- downloads: 1000,
321
- updated: new Date().toISOString(),
322
- },
323
- {
324
- name: '@wundr/plugin-docker',
325
- version: '1.2.0',
326
- description: 'Docker integration plugin',
327
- downloads: 800,
328
- updated: new Date().toISOString(),
329
- },
330
- ];
322
+ if (!(await fs.pathExists(this.pluginsDir))) {
323
+ logger.debug(`Plugin directory not found: ${this.pluginsDir}`);
324
+ return [];
325
+ }
326
+
327
+ const entries = await fs.readdir(this.pluginsDir);
328
+ const plugins: any[] = [];
329
+
330
+ for (const entry of entries) {
331
+ const entryPath = path.join(this.pluginsDir, entry);
332
+ const packageJsonPath = path.join(entryPath, 'package.json');
333
+
334
+ if (!(await fs.pathExists(packageJsonPath))) {
335
+ continue;
336
+ }
337
+
338
+ try {
339
+ const packageJson = await fs.readJson(packageJsonPath);
340
+ const stat = await fs.stat(entryPath);
341
+ plugins.push({
342
+ name: packageJson.name || entry,
343
+ version: packageJson.version || 'unknown',
344
+ description: packageJson.description || '',
345
+ author: packageJson.author || '',
346
+ updated: stat.mtime.toISOString(),
347
+ });
348
+ } catch (parseError) {
349
+ logger.debug(
350
+ `Failed to read package.json for plugin ${entry}:`,
351
+ parseError
352
+ );
353
+ }
354
+ }
355
+
356
+ return plugins;
331
357
  } catch (error) {
332
358
  logger.debug('Failed to get available plugins:', error);
333
359
  return [];
@@ -2,7 +2,14 @@
2
2
  * Integration tests for computer-setup with Claude Code configuration
3
3
  */
4
4
 
5
- import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
5
+ import {
6
+ describe,
7
+ it,
8
+ expect,
9
+ beforeEach,
10
+ afterEach,
11
+ jest,
12
+ } from '@jest/globals';
6
13
  import * as fs from 'fs/promises';
7
14
  import * as path from 'path';
8
15
  import { existsSync } from 'fs';
@@ -79,7 +86,10 @@ describe('Computer Setup Integration Tests', () => {
79
86
  await fs.writeFile(testFile, 'original content');
80
87
 
81
88
  // Create backup
82
- const metadata = await backupManager.createBackup([testFile], 'Test backup');
89
+ const metadata = await backupManager.createBackup(
90
+ [testFile],
91
+ 'Test backup'
92
+ );
83
93
 
84
94
  // Modify file
85
95
  await fs.writeFile(testFile, 'modified content');
@@ -102,7 +112,10 @@ describe('Computer Setup Integration Tests', () => {
102
112
  const testFile = path.join(testDir, 'test.txt');
103
113
  await fs.writeFile(testFile, 'content');
104
114
 
105
- const metadata = await backupManager.createBackup([testFile], 'Test backup');
115
+ const metadata = await backupManager.createBackup(
116
+ [testFile],
117
+ 'Test backup'
118
+ );
106
119
 
107
120
  const isValid = await backupManager.verifyBackup(metadata.backupId);
108
121
  expect(isValid).toBe(true);
@@ -206,7 +219,9 @@ describe('Computer Setup Integration Tests', () => {
206
219
  const conventionsPath = path.join(claudeDir, 'conventions.json');
207
220
  expect(existsSync(conventionsPath)).toBe(true);
208
221
 
209
- const conventions = JSON.parse(await fs.readFile(conventionsPath, 'utf-8'));
222
+ const conventions = JSON.parse(
223
+ await fs.readFile(conventionsPath, 'utf-8')
224
+ );
210
225
  expect(conventions).toHaveProperty('fileNaming');
211
226
  expect(conventions).toHaveProperty('codeStyle');
212
227
  });
@@ -220,9 +235,15 @@ describe('Computer Setup Integration Tests', () => {
220
235
  expect(result.success).toBe(true);
221
236
 
222
237
  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);
238
+ expect(existsSync(path.join(agentsDir, 'backend-developer.json'))).toBe(
239
+ true
240
+ );
241
+ expect(existsSync(path.join(agentsDir, 'frontend-developer.json'))).toBe(
242
+ true
243
+ );
244
+ expect(existsSync(path.join(agentsDir, 'fullstack-developer.json'))).toBe(
245
+ true
246
+ );
226
247
  });
227
248
 
228
249
  it('should install git-worktree workflows', async () => {
@@ -279,7 +300,10 @@ describe('Computer Setup Integration Tests', () => {
279
300
  expect(result.skipped).toContain('CLAUDE.md');
280
301
 
281
302
  // Content should remain unchanged
282
- const content = await fs.readFile(path.join(claudeDir, 'CLAUDE.md'), 'utf-8');
303
+ const content = await fs.readFile(
304
+ path.join(claudeDir, 'CLAUDE.md'),
305
+ 'utf-8'
306
+ );
283
307
  expect(content).toBe('existing content');
284
308
  });
285
309
 
@@ -296,7 +320,10 @@ describe('Computer Setup Integration Tests', () => {
296
320
  expect(result.installed).toContain('CLAUDE.md');
297
321
 
298
322
  // Content should be updated
299
- const content = await fs.readFile(path.join(claudeDir, 'CLAUDE.md'), 'utf-8');
323
+ const content = await fs.readFile(
324
+ path.join(claudeDir, 'CLAUDE.md'),
325
+ 'utf-8'
326
+ );
300
327
  expect(content).toContain('Test content');
301
328
  });
302
329
 
@@ -347,16 +374,20 @@ describe('Computer Setup Integration Tests', () => {
347
374
  // Verify all components installed
348
375
  expect(existsSync(path.join(claudeDir, 'CLAUDE.md'))).toBe(true);
349
376
  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(
377
+ expect(existsSync(path.join(claudeDir, 'hooks', 'pre-commit'))).toBe(
352
378
  true
353
379
  );
354
380
  expect(
355
- existsSync(path.join(claudeDir, 'workflows', 'feature-development.json'))
381
+ existsSync(path.join(claudeDir, 'agents', 'backend-developer.json'))
382
+ ).toBe(true);
383
+ expect(
384
+ existsSync(
385
+ path.join(claudeDir, 'workflows', 'feature-development.json')
386
+ )
387
+ ).toBe(true);
388
+ expect(
389
+ existsSync(path.join(claudeDir, 'scripts', 'validate-setup.sh'))
356
390
  ).toBe(true);
357
- expect(existsSync(path.join(claudeDir, 'scripts', 'validate-setup.sh'))).toBe(
358
- true
359
- );
360
391
  });
361
392
 
362
393
  it('should support complete backup and rollback cycle', async () => {
@@ -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