@claude-flow/cli 3.0.0-alpha.10 → 3.0.0-alpha.12

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 (84) hide show
  1. package/.agentic-flow/intelligence.json +4 -4
  2. package/.claude-flow/daemon-state.json +35 -47
  3. package/.claude-flow/metrics/codebase-map.json +2 -2
  4. package/.claude-flow/metrics/consolidation.json +1 -1
  5. package/.claude-flow/metrics/performance.json +3 -3
  6. package/.claude-flow/metrics/security-audit.json +1 -1
  7. package/.claude-flow/metrics/task-metrics.json +3 -3
  8. package/.claude-flow/metrics/test-gaps.json +1 -1
  9. package/README.md +172 -6
  10. package/agents/architect.yaml +1 -1
  11. package/agents/coder.yaml +1 -1
  12. package/agents/reviewer.yaml +1 -1
  13. package/agents/security-architect.yaml +1 -1
  14. package/agents/tester.yaml +1 -1
  15. package/dist/src/commands/claims.d.ts +10 -0
  16. package/dist/src/commands/claims.d.ts.map +1 -0
  17. package/dist/src/commands/claims.js +288 -0
  18. package/dist/src/commands/claims.js.map +1 -0
  19. package/dist/src/commands/completions.d.ts +10 -0
  20. package/dist/src/commands/completions.d.ts.map +1 -0
  21. package/dist/src/commands/completions.js +539 -0
  22. package/dist/src/commands/completions.js.map +1 -0
  23. package/dist/src/commands/deployment.d.ts +10 -0
  24. package/dist/src/commands/deployment.d.ts.map +1 -0
  25. package/dist/src/commands/deployment.js +289 -0
  26. package/dist/src/commands/deployment.js.map +1 -0
  27. package/dist/src/commands/doctor.d.ts +10 -0
  28. package/dist/src/commands/doctor.d.ts.map +1 -0
  29. package/dist/src/commands/doctor.js +352 -0
  30. package/dist/src/commands/doctor.js.map +1 -0
  31. package/dist/src/commands/embeddings.d.ts +18 -0
  32. package/dist/src/commands/embeddings.d.ts.map +1 -0
  33. package/dist/src/commands/embeddings.js +616 -0
  34. package/dist/src/commands/embeddings.js.map +1 -0
  35. package/dist/src/commands/index.d.ts +10 -0
  36. package/dist/src/commands/index.d.ts.map +1 -1
  37. package/dist/src/commands/index.js +37 -1
  38. package/dist/src/commands/index.js.map +1 -1
  39. package/dist/src/commands/memory.js +2 -2
  40. package/dist/src/commands/memory.js.map +1 -1
  41. package/dist/src/commands/neural.d.ts +10 -0
  42. package/dist/src/commands/neural.d.ts.map +1 -0
  43. package/dist/src/commands/neural.js +224 -0
  44. package/dist/src/commands/neural.js.map +1 -0
  45. package/dist/src/commands/performance.d.ts +10 -0
  46. package/dist/src/commands/performance.d.ts.map +1 -0
  47. package/dist/src/commands/performance.js +262 -0
  48. package/dist/src/commands/performance.js.map +1 -0
  49. package/dist/src/commands/plugins.d.ts +10 -0
  50. package/dist/src/commands/plugins.d.ts.map +1 -0
  51. package/dist/src/commands/plugins.js +280 -0
  52. package/dist/src/commands/plugins.js.map +1 -0
  53. package/dist/src/commands/providers.d.ts +10 -0
  54. package/dist/src/commands/providers.d.ts.map +1 -0
  55. package/dist/src/commands/providers.js +232 -0
  56. package/dist/src/commands/providers.js.map +1 -0
  57. package/dist/src/commands/security.d.ts +10 -0
  58. package/dist/src/commands/security.d.ts.map +1 -0
  59. package/dist/src/commands/security.js +261 -0
  60. package/dist/src/commands/security.js.map +1 -0
  61. package/dist/src/index.d.ts +2 -0
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +19 -2
  64. package/dist/src/index.js.map +1 -1
  65. package/dist/src/suggest.d.ts +53 -0
  66. package/dist/src/suggest.d.ts.map +1 -0
  67. package/dist/src/suggest.js +200 -0
  68. package/dist/src/suggest.js.map +1 -0
  69. package/dist/tsconfig.tsbuildinfo +1 -1
  70. package/package.json +1 -1
  71. package/src/commands/claims.ts +317 -0
  72. package/src/commands/completions.ts +558 -0
  73. package/src/commands/deployment.ts +323 -0
  74. package/src/commands/doctor.ts +378 -0
  75. package/src/commands/embeddings.ts +686 -0
  76. package/src/commands/index.ts +37 -1
  77. package/src/commands/memory.ts +2 -2
  78. package/src/commands/neural.ts +253 -0
  79. package/src/commands/performance.ts +292 -0
  80. package/src/commands/plugins.ts +316 -0
  81. package/src/commands/providers.ts +259 -0
  82. package/src/commands/security.ts +288 -0
  83. package/src/index.ts +19 -3
  84. package/src/suggest.ts +245 -0
@@ -0,0 +1,288 @@
1
+ /**
2
+ * V3 CLI Security Command
3
+ * Security scanning, CVE detection, threat modeling, vulnerability management
4
+ *
5
+ * Created with ❤️ by ruv.io
6
+ */
7
+
8
+ import type { Command, CommandContext, CommandResult } from '../types.js';
9
+ import { output } from '../output.js';
10
+
11
+ // Scan subcommand
12
+ const scanCommand: Command = {
13
+ name: 'scan',
14
+ description: 'Run security scan on target (code, dependencies, containers)',
15
+ options: [
16
+ { name: 'target', short: 't', type: 'string', description: 'Target path or URL to scan', default: '.' },
17
+ { name: 'depth', short: 'd', type: 'string', description: 'Scan depth: quick, standard, deep', default: 'standard' },
18
+ { name: 'type', type: 'string', description: 'Scan type: code, deps, container, all', default: 'all' },
19
+ { name: 'output', short: 'o', type: 'string', description: 'Output format: text, json, sarif', default: 'text' },
20
+ { name: 'fix', short: 'f', type: 'boolean', description: 'Auto-fix vulnerabilities where possible' },
21
+ ],
22
+ examples: [
23
+ { command: 'claude-flow security scan -t ./src', description: 'Scan source directory' },
24
+ { command: 'claude-flow security scan --depth deep --fix', description: 'Deep scan with auto-fix' },
25
+ ],
26
+ action: async (ctx: CommandContext): Promise<CommandResult> => {
27
+ const target = ctx.flags.target as string || '.';
28
+ const depth = ctx.flags.depth as string || 'standard';
29
+ const scanType = ctx.flags.type as string || 'all';
30
+
31
+ output.writeln();
32
+ output.writeln(output.bold('Security Scan'));
33
+ output.writeln(output.dim('─'.repeat(50)));
34
+
35
+ const spinner = output.createSpinner({ text: `Scanning ${target}...`, spinner: 'dots' });
36
+ spinner.start();
37
+
38
+ // Simulate scan phases
39
+ const phases = ['Analyzing code patterns', 'Checking dependencies', 'CVE database lookup', 'Generating report'];
40
+ for (const phase of phases) {
41
+ spinner.setText(phase + '...');
42
+ await new Promise(r => setTimeout(r, 400));
43
+ }
44
+
45
+ spinner.succeed('Scan complete');
46
+
47
+ output.writeln();
48
+ output.printTable({
49
+ columns: [
50
+ { key: 'severity', header: 'Severity', width: 12 },
51
+ { key: 'type', header: 'Type', width: 18 },
52
+ { key: 'location', header: 'Location', width: 25 },
53
+ { key: 'description', header: 'Description', width: 35 },
54
+ ],
55
+ data: [
56
+ { severity: output.error('CRITICAL'), type: 'CVE-2024-1234', location: 'package.json:45', description: 'Prototype pollution in lodash' },
57
+ { severity: output.warning('HIGH'), type: 'Hardcoded Secret', location: 'src/config.ts:12', description: 'API key exposed in source' },
58
+ { severity: output.warning('MEDIUM'), type: 'SQL Injection', location: 'src/db/query.ts:78', description: 'Unsanitized user input' },
59
+ { severity: output.info('LOW'), type: 'Outdated Dep', location: 'package.json:23', description: 'axios@0.21.0 has known issues' },
60
+ ],
61
+ });
62
+
63
+ output.writeln();
64
+ output.printBox([
65
+ `Target: ${target}`,
66
+ `Depth: ${depth}`,
67
+ `Type: ${scanType}`,
68
+ ``,
69
+ `Critical: 1 High: 1 Medium: 1 Low: 1`,
70
+ `Total Issues: 4`,
71
+ ].join('\n'), 'Scan Summary');
72
+
73
+ return { success: true };
74
+ },
75
+ };
76
+
77
+ // CVE subcommand
78
+ const cveCommand: Command = {
79
+ name: 'cve',
80
+ description: 'Check and manage CVE vulnerabilities',
81
+ options: [
82
+ { name: 'check', short: 'c', type: 'string', description: 'Check specific CVE ID' },
83
+ { name: 'list', short: 'l', type: 'boolean', description: 'List all known CVEs' },
84
+ { name: 'severity', short: 's', type: 'string', description: 'Filter by severity: critical, high, medium, low' },
85
+ ],
86
+ examples: [
87
+ { command: 'claude-flow security cve --list', description: 'List all CVEs' },
88
+ { command: 'claude-flow security cve -c CVE-2024-1234', description: 'Check specific CVE' },
89
+ ],
90
+ action: async (ctx: CommandContext): Promise<CommandResult> => {
91
+ const checkCve = ctx.flags.check as string;
92
+
93
+ output.writeln();
94
+ output.writeln(output.bold('CVE Database'));
95
+ output.writeln(output.dim('─'.repeat(50)));
96
+
97
+ if (checkCve) {
98
+ output.printBox([
99
+ `CVE ID: ${checkCve}`,
100
+ `Severity: CRITICAL (9.8)`,
101
+ `Status: Active`,
102
+ ``,
103
+ `Description: Remote code execution vulnerability`,
104
+ `Affected: lodash < 4.17.21`,
105
+ `Fix: Upgrade to lodash >= 4.17.21`,
106
+ ``,
107
+ `References:`,
108
+ ` - https://nvd.nist.gov/vuln/detail/${checkCve}`,
109
+ ` - https://github.com/advisories`,
110
+ ].join('\n'), 'CVE Details');
111
+ } else {
112
+ output.printTable({
113
+ columns: [
114
+ { key: 'id', header: 'CVE ID', width: 18 },
115
+ { key: 'severity', header: 'Severity', width: 12 },
116
+ { key: 'package', header: 'Package', width: 20 },
117
+ { key: 'status', header: 'Status', width: 15 },
118
+ ],
119
+ data: [
120
+ { id: 'CVE-2024-1234', severity: output.error('CRITICAL'), package: 'lodash@4.17.20', status: output.warning('Unfixed') },
121
+ { id: 'CVE-2024-5678', severity: output.warning('HIGH'), package: 'axios@0.21.0', status: output.success('Fixed') },
122
+ { id: 'CVE-2024-9012', severity: output.info('MEDIUM'), package: 'express@4.17.0', status: output.success('Fixed') },
123
+ ],
124
+ });
125
+ }
126
+
127
+ return { success: true };
128
+ },
129
+ };
130
+
131
+ // Threats subcommand
132
+ const threatsCommand: Command = {
133
+ name: 'threats',
134
+ description: 'Threat modeling and analysis',
135
+ options: [
136
+ { name: 'model', short: 'm', type: 'string', description: 'Threat model: stride, dread, pasta', default: 'stride' },
137
+ { name: 'scope', short: 's', type: 'string', description: 'Analysis scope', default: '.' },
138
+ { name: 'export', short: 'e', type: 'string', description: 'Export format: json, md, html' },
139
+ ],
140
+ examples: [
141
+ { command: 'claude-flow security threats --model stride', description: 'Run STRIDE analysis' },
142
+ { command: 'claude-flow security threats -e md', description: 'Export as markdown' },
143
+ ],
144
+ action: async (ctx: CommandContext): Promise<CommandResult> => {
145
+ const model = ctx.flags.model as string || 'stride';
146
+
147
+ output.writeln();
148
+ output.writeln(output.bold(`Threat Model: ${model.toUpperCase()}`));
149
+ output.writeln(output.dim('─'.repeat(50)));
150
+
151
+ output.printTable({
152
+ columns: [
153
+ { key: 'category', header: 'Category', width: 20 },
154
+ { key: 'threat', header: 'Threat', width: 30 },
155
+ { key: 'risk', header: 'Risk', width: 10 },
156
+ { key: 'mitigation', header: 'Mitigation', width: 30 },
157
+ ],
158
+ data: [
159
+ { category: 'Spoofing', threat: 'API key theft', risk: output.error('High'), mitigation: 'Use secure key storage' },
160
+ { category: 'Tampering', threat: 'Data manipulation', risk: output.warning('Medium'), mitigation: 'Input validation' },
161
+ { category: 'Repudiation', threat: 'Action denial', risk: output.info('Low'), mitigation: 'Audit logging' },
162
+ { category: 'Info Disclosure', threat: 'Data leakage', risk: output.error('High'), mitigation: 'Encryption at rest' },
163
+ { category: 'DoS', threat: 'Resource exhaustion', risk: output.warning('Medium'), mitigation: 'Rate limiting' },
164
+ { category: 'Elevation', threat: 'Privilege escalation', risk: output.error('High'), mitigation: 'RBAC implementation' },
165
+ ],
166
+ });
167
+
168
+ return { success: true };
169
+ },
170
+ };
171
+
172
+ // Audit subcommand
173
+ const auditCommand: Command = {
174
+ name: 'audit',
175
+ description: 'Security audit logging and compliance',
176
+ options: [
177
+ { name: 'action', short: 'a', type: 'string', description: 'Action: log, list, export, clear', default: 'list' },
178
+ { name: 'limit', short: 'l', type: 'number', description: 'Number of entries to show', default: '20' },
179
+ { name: 'filter', short: 'f', type: 'string', description: 'Filter by event type' },
180
+ ],
181
+ examples: [
182
+ { command: 'claude-flow security audit --action list', description: 'List audit logs' },
183
+ { command: 'claude-flow security audit -a export', description: 'Export audit trail' },
184
+ ],
185
+ action: async (ctx: CommandContext): Promise<CommandResult> => {
186
+ const action = ctx.flags.action as string || 'list';
187
+
188
+ output.writeln();
189
+ output.writeln(output.bold('Security Audit Log'));
190
+ output.writeln(output.dim('─'.repeat(60)));
191
+
192
+ output.printTable({
193
+ columns: [
194
+ { key: 'timestamp', header: 'Timestamp', width: 22 },
195
+ { key: 'event', header: 'Event', width: 20 },
196
+ { key: 'user', header: 'User', width: 15 },
197
+ { key: 'status', header: 'Status', width: 12 },
198
+ ],
199
+ data: [
200
+ { timestamp: '2024-01-15 14:32:01', event: 'AUTH_LOGIN', user: 'admin', status: output.success('Success') },
201
+ { timestamp: '2024-01-15 14:30:45', event: 'CONFIG_CHANGE', user: 'system', status: output.success('Success') },
202
+ { timestamp: '2024-01-15 14:28:12', event: 'AUTH_FAILED', user: 'unknown', status: output.error('Failed') },
203
+ { timestamp: '2024-01-15 14:25:33', event: 'SCAN_COMPLETE', user: 'ci-bot', status: output.success('Success') },
204
+ { timestamp: '2024-01-15 14:20:00', event: 'KEY_ROTATE', user: 'admin', status: output.success('Success') },
205
+ ],
206
+ });
207
+
208
+ return { success: true };
209
+ },
210
+ };
211
+
212
+ // Secrets subcommand
213
+ const secretsCommand: Command = {
214
+ name: 'secrets',
215
+ description: 'Detect and manage secrets in codebase',
216
+ options: [
217
+ { name: 'action', short: 'a', type: 'string', description: 'Action: scan, list, rotate', default: 'scan' },
218
+ { name: 'path', short: 'p', type: 'string', description: 'Path to scan', default: '.' },
219
+ { name: 'ignore', short: 'i', type: 'string', description: 'Patterns to ignore' },
220
+ ],
221
+ examples: [
222
+ { command: 'claude-flow security secrets --action scan', description: 'Scan for secrets' },
223
+ { command: 'claude-flow security secrets -a rotate', description: 'Rotate compromised secrets' },
224
+ ],
225
+ action: async (ctx: CommandContext): Promise<CommandResult> => {
226
+ const path = ctx.flags.path as string || '.';
227
+
228
+ output.writeln();
229
+ output.writeln(output.bold('Secret Detection'));
230
+ output.writeln(output.dim('─'.repeat(50)));
231
+
232
+ const spinner = output.createSpinner({ text: 'Scanning for secrets...', spinner: 'dots' });
233
+ spinner.start();
234
+ await new Promise(r => setTimeout(r, 800));
235
+ spinner.succeed('Scan complete');
236
+
237
+ output.writeln();
238
+ output.printTable({
239
+ columns: [
240
+ { key: 'type', header: 'Secret Type', width: 20 },
241
+ { key: 'location', header: 'Location', width: 30 },
242
+ { key: 'risk', header: 'Risk', width: 12 },
243
+ { key: 'action', header: 'Recommended', width: 20 },
244
+ ],
245
+ data: [
246
+ { type: 'AWS Access Key', location: 'src/config.ts:15', risk: output.error('Critical'), action: 'Rotate immediately' },
247
+ { type: 'GitHub Token', location: '.env.example:8', risk: output.warning('High'), action: 'Remove from repo' },
248
+ { type: 'JWT Secret', location: 'src/auth.ts:42', risk: output.warning('High'), action: 'Use env variable' },
249
+ { type: 'DB Password', location: 'docker-compose.yml:23', risk: output.warning('Medium'), action: 'Use secrets mgmt' },
250
+ ],
251
+ });
252
+
253
+ return { success: true };
254
+ },
255
+ };
256
+
257
+ // Main security command
258
+ export const securityCommand: Command = {
259
+ name: 'security',
260
+ description: 'Security scanning, CVE detection, threat modeling, vulnerability management',
261
+ subcommands: [scanCommand, cveCommand, threatsCommand, auditCommand, secretsCommand],
262
+ examples: [
263
+ { command: 'claude-flow security scan', description: 'Run security scan' },
264
+ { command: 'claude-flow security cve --list', description: 'List known CVEs' },
265
+ { command: 'claude-flow security threats', description: 'Run threat analysis' },
266
+ ],
267
+ action: async (): Promise<CommandResult> => {
268
+ output.writeln();
269
+ output.writeln(output.bold('Claude Flow Security Suite'));
270
+ output.writeln(output.dim('Comprehensive security scanning and vulnerability management'));
271
+ output.writeln();
272
+ output.writeln('Subcommands:');
273
+ output.printList([
274
+ 'scan - Run security scans on code, deps, containers',
275
+ 'cve - Check and manage CVE vulnerabilities',
276
+ 'threats - Threat modeling (STRIDE, DREAD, PASTA)',
277
+ 'audit - Security audit logging and compliance',
278
+ 'secrets - Detect and manage secrets in codebase',
279
+ ]);
280
+ output.writeln();
281
+ output.writeln('Use --help with subcommands for more info');
282
+ output.writeln();
283
+ output.writeln(output.dim('Created with ❤️ by ruv.io'));
284
+ return { success: true };
285
+ },
286
+ };
287
+
288
+ export default securityCommand;
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * V3 CLI Main Entry Point
3
3
  * Modernized CLI for Claude Flow V3
4
+ *
5
+ * Created with ❤️ by ruv.io
4
6
  */
5
7
 
6
8
  import { readFileSync } from 'fs';
@@ -9,7 +11,8 @@ import { dirname, join } from 'path';
9
11
  import type { Command, CommandContext, CommandResult, V3Config, CLIError } from './types.js';
10
12
  import { CommandParser, commandParser } from './parser.js';
11
13
  import { OutputFormatter, output } from './output.js';
12
- import { commands, commandRegistry, getCommand } from './commands/index.js';
14
+ import { commands, commandRegistry, getCommand, getCommandNames } from './commands/index.js';
15
+ import { suggestCommand } from './suggest.js';
13
16
 
14
17
  // Read version from package.json at runtime
15
18
  function getPackageVersion(): string {
@@ -93,11 +96,19 @@ export class CLI {
93
96
  this.output.printDebug(`CWD: ${process.cwd()}`);
94
97
  }
95
98
 
96
- // No command - show help
99
+ // No command - show help or suggest correction
97
100
  if (commandPath.length === 0 || flags.help || flags.h) {
98
101
  if (commandPath.length > 0) {
99
102
  // Show command-specific help
100
103
  this.showCommandHelp(commandPath[0]);
104
+ } else if (positional.length > 0 && !positional[0].startsWith('-')) {
105
+ // First positional looks like an attempted command - suggest correction
106
+ const attemptedCommand = positional[0];
107
+ this.output.printError(`Unknown command: ${attemptedCommand}`);
108
+ const availableCommands = Array.from(new Set(commands.map(c => c.name)));
109
+ const { message } = suggestCommand(attemptedCommand, availableCommands);
110
+ this.output.writeln(this.output.dim(` ${message}`));
111
+ process.exit(1);
101
112
  } else {
102
113
  this.showHelp();
103
114
  }
@@ -112,7 +123,10 @@ export class CLI {
112
123
 
113
124
  if (!command) {
114
125
  this.output.printError(`Unknown command: ${commandName}`);
115
- this.output.writeln(`Run "${this.name} --help" for available commands`);
126
+ // Smart suggestions
127
+ const availableCommands = Array.from(new Set(commands.map(c => c.name)));
128
+ const { message } = suggestCommand(commandName, availableCommands);
129
+ this.output.writeln(this.output.dim(` ${message}`));
116
130
  process.exit(1);
117
131
  }
118
132
 
@@ -267,6 +281,8 @@ export class CLI {
267
281
 
268
282
  this.output.writeln(this.output.dim('Run "claude-flow <command> --help" for command help'));
269
283
  this.output.writeln();
284
+ this.output.writeln(this.output.dim('Created with ❤️ by ruv.io'));
285
+ this.output.writeln();
270
286
  }
271
287
 
272
288
  /**
package/src/suggest.ts ADDED
@@ -0,0 +1,245 @@
1
+ /**
2
+ * V3 CLI Smart Error Suggestions
3
+ * Levenshtein distance and command suggestions
4
+ *
5
+ * Created with ruv.io
6
+ */
7
+
8
+ /**
9
+ * Calculate Levenshtein distance between two strings
10
+ */
11
+ export function levenshteinDistance(a: string, b: string): number {
12
+ const m = a.length;
13
+ const n = b.length;
14
+
15
+ // Early termination for empty strings
16
+ if (m === 0) return n;
17
+ if (n === 0) return m;
18
+
19
+ // Create distance matrix
20
+ const d: number[][] = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
21
+
22
+ // Initialize first column
23
+ for (let i = 0; i <= m; i++) {
24
+ d[i][0] = i;
25
+ }
26
+
27
+ // Initialize first row
28
+ for (let j = 0; j <= n; j++) {
29
+ d[0][j] = j;
30
+ }
31
+
32
+ // Fill in the rest of the matrix
33
+ for (let j = 1; j <= n; j++) {
34
+ for (let i = 1; i <= m; i++) {
35
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
36
+ d[i][j] = Math.min(
37
+ d[i - 1][j] + 1, // deletion
38
+ d[i][j - 1] + 1, // insertion
39
+ d[i - 1][j - 1] + cost // substitution
40
+ );
41
+ }
42
+ }
43
+
44
+ return d[m][n];
45
+ }
46
+
47
+ /**
48
+ * Calculate similarity score (0-1) between two strings
49
+ */
50
+ export function similarityScore(a: string, b: string): number {
51
+ const maxLen = Math.max(a.length, b.length);
52
+ if (maxLen === 0) return 1;
53
+ const distance = levenshteinDistance(a.toLowerCase(), b.toLowerCase());
54
+ return 1 - distance / maxLen;
55
+ }
56
+
57
+ /**
58
+ * Find similar strings from a list
59
+ */
60
+ export function findSimilar(
61
+ input: string,
62
+ candidates: string[],
63
+ options: {
64
+ maxSuggestions?: number;
65
+ minSimilarity?: number;
66
+ maxDistance?: number;
67
+ } = {}
68
+ ): string[] {
69
+ const {
70
+ maxSuggestions = 3,
71
+ minSimilarity = 0.4,
72
+ maxDistance = 3
73
+ } = options;
74
+
75
+ const inputLower = input.toLowerCase();
76
+
77
+ // Score all candidates
78
+ const scored = candidates
79
+ .map(candidate => ({
80
+ candidate,
81
+ distance: levenshteinDistance(inputLower, candidate.toLowerCase()),
82
+ similarity: similarityScore(inputLower, candidate),
83
+ // Boost prefix matches
84
+ prefixBoost: candidate.toLowerCase().startsWith(inputLower) ? 0.3 : 0
85
+ }))
86
+ .filter(s => s.distance <= maxDistance || s.similarity >= minSimilarity)
87
+ .map(s => ({
88
+ ...s,
89
+ score: s.similarity + s.prefixBoost
90
+ }))
91
+ .sort((a, b) => b.score - a.score)
92
+ .slice(0, maxSuggestions);
93
+
94
+ return scored.map(s => s.candidate);
95
+ }
96
+
97
+ /**
98
+ * Format suggestion message for CLI errors
99
+ */
100
+ export function formatSuggestion(
101
+ invalidInput: string,
102
+ suggestions: string[],
103
+ context: 'command' | 'subcommand' | 'option' | 'value' = 'command'
104
+ ): string {
105
+ if (suggestions.length === 0) {
106
+ return '';
107
+ }
108
+
109
+ const contextMap = {
110
+ command: 'Did you mean',
111
+ subcommand: 'Available subcommands',
112
+ option: 'Did you mean',
113
+ value: 'Valid values'
114
+ };
115
+
116
+ const prefix = contextMap[context];
117
+
118
+ if (suggestions.length === 1) {
119
+ return `\n ${prefix}: ${suggestions[0]}`;
120
+ }
121
+
122
+ return `\n ${prefix}:\n${suggestions.map(s => ` - ${s}`).join('\n')}`;
123
+ }
124
+
125
+ /**
126
+ * Common typos and their corrections
127
+ */
128
+ export const COMMON_TYPOS: Record<string, string> = {
129
+ 'init': 'init',
130
+ 'initi': 'init',
131
+ 'inizialize': 'init',
132
+ 'staus': 'status',
133
+ 'stauts': 'status',
134
+ 'stats': 'stats',
135
+ 'stat': 'status',
136
+ 'swarrm': 'swarm',
137
+ 'swarn': 'swarm',
138
+ 'agnet': 'agent',
139
+ 'agen': 'agent',
140
+ 'memroy': 'memory',
141
+ 'mem': 'memory',
142
+ 'memmory': 'memory',
143
+ 'confg': 'config',
144
+ 'conf': 'config',
145
+ 'configu': 'config',
146
+ 'hook': 'hooks',
147
+ 'hoks': 'hooks',
148
+ 'hive': 'hive-mind',
149
+ 'hivemind': 'hive-mind',
150
+ 'hive_mind': 'hive-mind',
151
+ 'neurl': 'neural',
152
+ 'nueral': 'neural',
153
+ 'securty': 'security',
154
+ 'sec': 'security',
155
+ 'perf': 'performance',
156
+ 'performace': 'performance',
157
+ 'provider': 'providers',
158
+ 'plugin': 'plugins',
159
+ 'dep': 'deployment',
160
+ 'depoly': 'deployment',
161
+ 'deploy': 'deployment',
162
+ 'claim': 'claims',
163
+ 'embed': 'embeddings',
164
+ 'embeding': 'embeddings',
165
+ 'daemon': 'daemon',
166
+ 'deamon': 'daemon',
167
+ 'doc': 'doctor',
168
+ 'docter': 'doctor',
169
+ 'complete': 'completions',
170
+ 'completion': 'completions',
171
+ 'comp': 'completions',
172
+ 'task': 'task',
173
+ 'taks': 'task',
174
+ 'sessio': 'session',
175
+ 'sess': 'session',
176
+ 'sesssion': 'session',
177
+ 'workflow': 'workflow',
178
+ 'wf': 'workflow',
179
+ 'wokflow': 'workflow'
180
+ };
181
+
182
+ /**
183
+ * Get corrected command if it's a common typo
184
+ */
185
+ export function getTypoCorrection(input: string): string | undefined {
186
+ return COMMON_TYPOS[input.toLowerCase()];
187
+ }
188
+
189
+ /**
190
+ * Smart command suggestion for unknown commands
191
+ */
192
+ export function suggestCommand(
193
+ unknownCommand: string,
194
+ availableCommands: string[]
195
+ ): {
196
+ correction?: string;
197
+ suggestions: string[];
198
+ message: string;
199
+ } {
200
+ // Check for common typo first
201
+ const correction = getTypoCorrection(unknownCommand);
202
+ if (correction && availableCommands.includes(correction)) {
203
+ return {
204
+ correction,
205
+ suggestions: [correction],
206
+ message: `Did you mean "${correction}"?`
207
+ };
208
+ }
209
+
210
+ // Find similar commands
211
+ const suggestions = findSimilar(unknownCommand, availableCommands, {
212
+ maxSuggestions: 3,
213
+ minSimilarity: 0.3,
214
+ maxDistance: 4
215
+ });
216
+
217
+ if (suggestions.length === 0) {
218
+ return {
219
+ suggestions: [],
220
+ message: 'Run "claude-flow --help" to see available commands.'
221
+ };
222
+ }
223
+
224
+ if (suggestions.length === 1) {
225
+ return {
226
+ suggestions,
227
+ message: `Did you mean "${suggestions[0]}"?`
228
+ };
229
+ }
230
+
231
+ return {
232
+ suggestions,
233
+ message: `Did you mean one of these?\n${suggestions.map(s => ` - ${s}`).join('\n')}`
234
+ };
235
+ }
236
+
237
+ export default {
238
+ levenshteinDistance,
239
+ similarityScore,
240
+ findSimilar,
241
+ formatSuggestion,
242
+ suggestCommand,
243
+ getTypoCorrection,
244
+ COMMON_TYPOS
245
+ };