cmp-standards 2.8.1 → 3.1.0

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 (119) hide show
  1. package/dist/analytics/CrossProjectAnalytics.d.ts +128 -0
  2. package/dist/analytics/CrossProjectAnalytics.d.ts.map +1 -0
  3. package/dist/analytics/CrossProjectAnalytics.js +434 -0
  4. package/dist/analytics/CrossProjectAnalytics.js.map +1 -0
  5. package/dist/analytics/index.d.ts +1 -0
  6. package/dist/analytics/index.d.ts.map +1 -1
  7. package/dist/analytics/index.js +2 -0
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/cache/EmbeddingCache.d.ts +6 -4
  10. package/dist/cache/EmbeddingCache.d.ts.map +1 -1
  11. package/dist/cache/EmbeddingCache.js +28 -17
  12. package/dist/cache/EmbeddingCache.js.map +1 -1
  13. package/dist/cli/index.js +658 -141
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/ui.d.ts +134 -0
  16. package/dist/cli/ui.d.ts.map +1 -0
  17. package/dist/cli/ui.js +311 -0
  18. package/dist/cli/ui.js.map +1 -0
  19. package/dist/dashboard/tokens.d.ts +228 -0
  20. package/dist/dashboard/tokens.d.ts.map +1 -0
  21. package/dist/dashboard/tokens.js +450 -0
  22. package/dist/dashboard/tokens.js.map +1 -0
  23. package/dist/dashboard/ui.d.ts +3 -0
  24. package/dist/dashboard/ui.d.ts.map +1 -1
  25. package/dist/dashboard/ui.js +95 -61
  26. package/dist/dashboard/ui.js.map +1 -1
  27. package/dist/db/cloud.d.ts +11 -0
  28. package/dist/db/cloud.d.ts.map +1 -1
  29. package/dist/db/cloud.js +49 -1
  30. package/dist/db/cloud.js.map +1 -1
  31. package/dist/db/migrations.d.ts +1 -0
  32. package/dist/db/migrations.d.ts.map +1 -1
  33. package/dist/db/migrations.js +109 -0
  34. package/dist/db/migrations.js.map +1 -1
  35. package/dist/db/turso-client.d.ts.map +1 -1
  36. package/dist/db/turso-client.js +3 -0
  37. package/dist/db/turso-client.js.map +1 -1
  38. package/dist/events/EventBus.d.ts +21 -0
  39. package/dist/events/EventBus.d.ts.map +1 -1
  40. package/dist/events/EventBus.js +81 -30
  41. package/dist/events/EventBus.js.map +1 -1
  42. package/dist/events/index.d.ts +1 -1
  43. package/dist/events/index.d.ts.map +1 -1
  44. package/dist/events/index.js +1 -1
  45. package/dist/events/index.js.map +1 -1
  46. package/dist/hooks/index.d.ts +1 -0
  47. package/dist/hooks/index.d.ts.map +1 -1
  48. package/dist/hooks/index.js +2 -0
  49. package/dist/hooks/index.js.map +1 -1
  50. package/dist/hooks/startup-verify.d.ts +31 -0
  51. package/dist/hooks/startup-verify.d.ts.map +1 -0
  52. package/dist/hooks/startup-verify.js +360 -0
  53. package/dist/hooks/startup-verify.js.map +1 -0
  54. package/dist/plugins/PluginManager.d.ts +160 -0
  55. package/dist/plugins/PluginManager.d.ts.map +1 -0
  56. package/dist/plugins/PluginManager.js +417 -0
  57. package/dist/plugins/PluginManager.js.map +1 -0
  58. package/dist/plugins/index.d.ts +7 -0
  59. package/dist/plugins/index.d.ts.map +1 -0
  60. package/dist/plugins/index.js +7 -0
  61. package/dist/plugins/index.js.map +1 -0
  62. package/dist/schema/expert-types.d.ts +2 -2
  63. package/dist/services/AuditLog.d.ts +205 -0
  64. package/dist/services/AuditLog.d.ts.map +1 -0
  65. package/dist/services/AuditLog.js +352 -0
  66. package/dist/services/AuditLog.js.map +1 -0
  67. package/dist/services/FeedbackCollector.d.ts +8 -0
  68. package/dist/services/FeedbackCollector.d.ts.map +1 -1
  69. package/dist/services/FeedbackCollector.js +19 -2
  70. package/dist/services/FeedbackCollector.js.map +1 -1
  71. package/dist/services/GitIntegration.d.ts +140 -0
  72. package/dist/services/GitIntegration.d.ts.map +1 -0
  73. package/dist/services/GitIntegration.js +423 -0
  74. package/dist/services/GitIntegration.js.map +1 -0
  75. package/dist/services/HookVerifier.d.ts +95 -0
  76. package/dist/services/HookVerifier.d.ts.map +1 -0
  77. package/dist/services/HookVerifier.js +493 -0
  78. package/dist/services/HookVerifier.js.map +1 -0
  79. package/dist/services/MemoryRelationshipService.d.ts +187 -0
  80. package/dist/services/MemoryRelationshipService.d.ts.map +1 -0
  81. package/dist/services/MemoryRelationshipService.js +375 -0
  82. package/dist/services/MemoryRelationshipService.js.map +1 -0
  83. package/dist/services/MemoryVersioning.d.ts +108 -0
  84. package/dist/services/MemoryVersioning.d.ts.map +1 -0
  85. package/dist/services/MemoryVersioning.js +281 -0
  86. package/dist/services/MemoryVersioning.js.map +1 -0
  87. package/dist/services/context-injector.d.ts +8 -0
  88. package/dist/services/context-injector.d.ts.map +1 -1
  89. package/dist/services/context-injector.js +19 -2
  90. package/dist/services/context-injector.js.map +1 -1
  91. package/dist/services/index.d.ts +5 -0
  92. package/dist/services/index.d.ts.map +1 -1
  93. package/dist/services/index.js +7 -0
  94. package/dist/services/index.js.map +1 -1
  95. package/dist/services/memory-router.d.ts +8 -0
  96. package/dist/services/memory-router.d.ts.map +1 -1
  97. package/dist/services/memory-router.js +19 -2
  98. package/dist/services/memory-router.js.map +1 -1
  99. package/dist/services/pattern-tracker.d.ts +13 -0
  100. package/dist/services/pattern-tracker.d.ts.map +1 -1
  101. package/dist/services/pattern-tracker.js +33 -3
  102. package/dist/services/pattern-tracker.js.map +1 -1
  103. package/dist/services/semantic-search.d.ts +12 -0
  104. package/dist/services/semantic-search.d.ts.map +1 -1
  105. package/dist/services/semantic-search.js +93 -17
  106. package/dist/services/semantic-search.js.map +1 -1
  107. package/dist/testing/index.d.ts +148 -0
  108. package/dist/testing/index.d.ts.map +1 -0
  109. package/dist/testing/index.js +370 -0
  110. package/dist/testing/index.js.map +1 -0
  111. package/dist/types/index.d.ts +1 -0
  112. package/dist/types/index.d.ts.map +1 -1
  113. package/dist/types/index.js +1 -0
  114. package/dist/types/index.js.map +1 -1
  115. package/dist/utils/resilience.d.ts +256 -0
  116. package/dist/utils/resilience.d.ts.map +1 -0
  117. package/dist/utils/resilience.js +499 -0
  118. package/dist/utils/resilience.js.map +1 -0
  119. package/package.json +12 -1
package/dist/cli/index.js CHANGED
@@ -27,6 +27,7 @@ import { getProjectRoot, getHooksDir } from '../utils/paths.js';
27
27
  import { RegistryGenerator } from '../registry/generator.js';
28
28
  import { PatternDetector } from '../auto-improve/pattern-detector.js';
29
29
  import { ESLintGenerator } from '../auto-improve/eslint-generator.js';
30
+ import { ui, withSpinner, runTasks } from './ui.js';
30
31
  const program = new Command();
31
32
  program
32
33
  .name('cmp-memory')
@@ -106,10 +107,8 @@ program
106
107
  .command('validate')
107
108
  .description('Validate project structure against standards')
108
109
  .action(async () => {
109
- console.log(chalk.blue('🔍 Validating Project Structure\n'));
110
+ ui.header('Validating Project Structure');
110
111
  const projectRoot = await getProjectRoot();
111
- const issues = [];
112
- const passed = [];
113
112
  // Check required files
114
113
  const requiredFiles = [
115
114
  'CLAUDE.md',
@@ -118,64 +117,79 @@ program
118
117
  '.claude/project.config.json',
119
118
  '.ai-skills/registry.json',
120
119
  ];
121
- for (const file of requiredFiles) {
122
- const filePath = path.join(projectRoot, file);
123
- try {
124
- await fs.access(filePath);
125
- passed.push(file);
126
- }
127
- catch {
128
- issues.push(`MISSING: ${file}`);
129
- }
130
- }
131
120
  // Check directories
132
121
  const requiredDirs = [
133
122
  '.claude/agents',
134
123
  '.claude/commands',
135
124
  '.claude/hooks',
136
125
  ];
137
- for (const dir of requiredDirs) {
138
- const dirPath = path.join(projectRoot, dir);
139
- try {
126
+ const fileTasks = requiredFiles.map(file => ({
127
+ name: `Check ${file}`,
128
+ task: async () => {
129
+ const filePath = path.join(projectRoot, file);
130
+ await fs.access(filePath);
131
+ },
132
+ }));
133
+ const dirTasks = requiredDirs.map(dir => ({
134
+ name: `Check ${dir}/`,
135
+ task: async () => {
136
+ const dirPath = path.join(projectRoot, dir);
140
137
  const stat = await fs.stat(dirPath);
141
- if (stat.isDirectory()) {
142
- const files = await fs.readdir(dirPath);
143
- if (files.length > 0) {
144
- passed.push(`${dir}/ (${files.length} files)`);
145
- }
146
- else {
147
- issues.push(`EMPTY: ${dir}/`);
148
- }
138
+ if (!stat.isDirectory())
139
+ throw new Error('Not a directory');
140
+ const files = await fs.readdir(dirPath);
141
+ if (files.length === 0)
142
+ throw new Error('Directory is empty');
143
+ },
144
+ }));
145
+ const expertTask = {
146
+ name: 'Check experts command',
147
+ task: async () => {
148
+ const expertsPath = path.join(projectRoot, '.claude/commands/experts.md');
149
+ await fs.access(expertsPath);
150
+ },
151
+ };
152
+ const hookVerifyTask = {
153
+ name: 'Verify hook configurations',
154
+ task: async () => {
155
+ const { HookVerifierService } = await import('../services/HookVerifier.js');
156
+ const verifier = new HookVerifierService(projectRoot);
157
+ const report = await verifier.verify(false);
158
+ if (!report.allValid) {
159
+ const issues = report.results.filter(r => r.status !== 'valid');
160
+ throw new Error(`${issues.length} hook(s) misconfigured. Run: cmp-standards verify-hooks --fix`);
149
161
  }
150
- }
151
- catch {
152
- issues.push(`MISSING: ${dir}/`);
153
- }
154
- }
155
- // Check experts command exists
156
- const expertsPath = path.join(projectRoot, '.claude/commands/experts.md');
157
- try {
158
- await fs.access(expertsPath);
159
- passed.push('.claude/commands/experts.md');
160
- }
161
- catch {
162
- issues.push('MISSING: .claude/commands/experts.md (run: cmp-memory sync --commands)');
163
- }
164
- // Summary
165
- console.log(chalk.green('✓ Passed:'));
166
- for (const p of passed) {
167
- console.log(chalk.green(` ${p}`));
162
+ },
163
+ };
164
+ const results = await runTasks([...fileTasks, ...dirTasks, expertTask, hookVerifyTask], { stopOnError: false });
165
+ const failed = results.filter(r => r.status === 'error');
166
+ if (failed.length > 0) {
167
+ ui.warning('Run: cmp-standards init --system YOUR_SYSTEM --force');
168
168
  }
169
- if (issues.length > 0) {
170
- console.log(chalk.red('\n✗ Issues:'));
171
- for (const issue of issues) {
172
- console.log(chalk.red(` ${issue}`));
173
- }
174
- console.log(chalk.yellow('\nRun: cmp-memory init --system YOUR_SYSTEM --force'));
169
+ });
170
+ // =============================================================================
171
+ // VERIFY-HOOKS COMMAND
172
+ // =============================================================================
173
+ program
174
+ .command('verify-hooks')
175
+ .description('Verify and fix hook configurations')
176
+ .option('--fix', 'Auto-fix hook issues where possible')
177
+ .option('-p, --project <path>', 'Project path (defaults to current directory)')
178
+ .option('--json', 'Output as JSON')
179
+ .action(async (options) => {
180
+ const { HookVerifierService, formatVerificationReport } = await import('../services/HookVerifier.js');
181
+ const projectPath = options.project ?? process.cwd();
182
+ const verifier = new HookVerifierService(projectPath);
183
+ const report = await verifier.verify(options.fix);
184
+ if (options.json) {
185
+ console.log(JSON.stringify(report, null, 2));
186
+ return;
175
187
  }
176
- else {
177
- console.log(chalk.green('\n✅ All validations passed!'));
188
+ console.log(formatVerificationReport(report));
189
+ if (!report.allValid && !options.fix) {
190
+ ui.warning('Run with --fix to auto-fix issues');
178
191
  }
192
+ process.exit(report.allValid ? 0 : 1);
179
193
  });
180
194
  // =============================================================================
181
195
  // SESSION-CONTEXT COMMAND (for hooks)
@@ -229,17 +243,21 @@ program
229
243
  .option('-i, --incremental', 'Only update changed files')
230
244
  .option('--files <files>', 'Specific files to process (comma-separated)')
231
245
  .action(async (options) => {
232
- console.log(chalk.blue('📚 Generating Knowledge Registry\n'));
246
+ ui.header('Generating Knowledge Registry');
233
247
  const generator = new RegistryGenerator();
234
248
  if (options.files) {
235
249
  const files = options.files.split(',').map((f) => f.trim());
236
- console.log(`Processing ${files.length} specific files...`);
237
- await generator.update(files);
250
+ await withSpinner(`Processing ${files.length} files`, async () => {
251
+ await generator.update(files);
252
+ }, { successText: `Processed ${files.length} files` });
238
253
  }
239
254
  else {
240
- await generator.generate();
255
+ await withSpinner('Generating registry', async (spinner) => {
256
+ spinner.text = 'Scanning documentation...';
257
+ await generator.generate();
258
+ }, { successText: 'Registry generated' });
241
259
  }
242
- console.log(chalk.green('\n✅ Registry generation complete!'));
260
+ ui.success('Registry generation complete!');
243
261
  });
244
262
  // =============================================================================
245
263
  // SCAN COMMAND
@@ -250,28 +268,36 @@ program
250
268
  .option('-d, --dir <directory>', 'Directory to scan', 'src')
251
269
  .option('-t, --threshold <number>', 'Pattern threshold', '3')
252
270
  .action(async (options) => {
253
- console.log(chalk.blue('🔍 Scanning for Patterns\n'));
271
+ ui.header('Scanning for Patterns');
254
272
  const projectRoot = await getProjectRoot();
255
273
  const config = await loadConfig(projectRoot);
256
274
  const detector = new PatternDetector(config);
257
- // Find TypeScript files
258
- const { glob } = await import('glob');
259
- const files = await glob(`${options.dir}/**/*.{ts,tsx}`, {
260
- cwd: projectRoot,
261
- absolute: true,
262
- ignore: ['**/node_modules/**', '**/*.d.ts', '**/*.test.ts'],
263
- });
264
- console.log(`Scanning ${files.length} files...`);
265
- for (const file of files) {
266
- const content = await fs.readFile(file, 'utf-8');
267
- detector.scan(content, file);
268
- }
275
+ // Find TypeScript files with spinner
276
+ const files = await withSpinner('Finding TypeScript files', async () => {
277
+ const { glob } = await import('glob');
278
+ return glob(`${options.dir}/**/*.{ts,tsx}`, {
279
+ cwd: projectRoot,
280
+ absolute: true,
281
+ ignore: ['**/node_modules/**', '**/*.d.ts', '**/*.test.ts'],
282
+ });
283
+ }, { successText: `Found files to scan` });
284
+ // Scan files with spinner
285
+ await withSpinner(`Scanning ${files.length} files`, async (spinner) => {
286
+ for (let i = 0; i < files.length; i++) {
287
+ const file = files[i];
288
+ const content = await fs.readFile(file, 'utf-8');
289
+ detector.scan(content, file);
290
+ spinner.text = `Scanning files (${i + 1}/${files.length})`;
291
+ }
292
+ }, { successText: `Scanned ${files.length} files` });
269
293
  const results = detector.getResults();
270
- console.log(chalk.blue('\n📊 Results:'));
271
- console.log(` Total patterns: ${results.total}`);
272
- console.log(` Triggered (≥${options.threshold}): ${results.triggered.length}`);
294
+ ui.subheader('Results');
295
+ ui.keyValue({
296
+ 'Total patterns': results.total,
297
+ [`Triggered (≥${options.threshold})`]: results.triggered.length,
298
+ });
273
299
  if (results.patterns.length > 0) {
274
- console.log(chalk.blue('\n📋 Detected Patterns:'));
300
+ ui.subheader('Detected Patterns');
275
301
  for (const pattern of results.patterns) {
276
302
  const icon = pattern.needsAutoImprove ? '🔴' : '⚪';
277
303
  const severity = chalk.gray(`[${pattern.severity}]`);
@@ -280,11 +306,11 @@ program
280
306
  }
281
307
  }
282
308
  if (results.triggered.length > 0) {
283
- console.log(chalk.yellow('\n⚠️ Patterns ready for auto-improvement:'));
309
+ ui.warning('Patterns ready for auto-improvement:');
284
310
  for (const pattern of results.triggered) {
285
311
  console.log(` - ${pattern.patternId} (${pattern.count} occurrences)`);
286
312
  }
287
- console.log(chalk.gray('\n Run: claude-memory improve'));
313
+ ui.dim('\n Run: cmp-standards improve');
288
314
  }
289
315
  });
290
316
  // =============================================================================
@@ -296,21 +322,27 @@ program
296
322
  .option('--dry-run', 'Show what would be done without making changes')
297
323
  .option('-p, --pattern <pattern>', 'Specific pattern to improve')
298
324
  .action(async (options) => {
299
- console.log(chalk.blue('🔧 Running Auto-Improvement\n'));
325
+ ui.header('Running Auto-Improvement');
300
326
  const projectRoot = await getProjectRoot();
301
327
  const config = await loadConfig(projectRoot);
302
- // First scan for patterns
328
+ // First scan for patterns with spinner
303
329
  const detector = new PatternDetector(config);
304
- const { glob } = await import('glob');
305
- const files = await glob('src/**/*.{ts,tsx}', {
306
- cwd: projectRoot,
307
- absolute: true,
308
- ignore: ['**/node_modules/**', '**/*.d.ts'],
330
+ const files = await withSpinner('Finding files to analyze', async () => {
331
+ const { glob } = await import('glob');
332
+ return glob('src/**/*.{ts,tsx}', {
333
+ cwd: projectRoot,
334
+ absolute: true,
335
+ ignore: ['**/node_modules/**', '**/*.d.ts'],
336
+ });
337
+ });
338
+ await withSpinner('Scanning for patterns', async (spinner) => {
339
+ for (let i = 0; i < files.length; i++) {
340
+ const file = files[i];
341
+ const content = await fs.readFile(file, 'utf-8');
342
+ detector.scan(content, file);
343
+ spinner.text = `Scanning patterns (${i + 1}/${files.length})`;
344
+ }
309
345
  });
310
- for (const file of files) {
311
- const content = await fs.readFile(file, 'utf-8');
312
- detector.scan(content, file);
313
- }
314
346
  const results = detector.getResults();
315
347
  // Filter patterns to improve
316
348
  let patternsToImprove = results.triggered;
@@ -318,31 +350,24 @@ program
318
350
  patternsToImprove = patternsToImprove.filter(p => p.patternId === options.pattern);
319
351
  }
320
352
  if (patternsToImprove.length === 0) {
321
- console.log(chalk.green('No patterns need improvement'));
353
+ ui.success('No patterns need improvement');
322
354
  return;
323
355
  }
324
- console.log(`Found ${patternsToImprove.length} patterns to improve:`);
356
+ ui.info(`Found ${patternsToImprove.length} patterns to improve:`);
325
357
  for (const pattern of patternsToImprove) {
326
- console.log(` - ${pattern.patternId}`);
358
+ ui.dim(` - ${pattern.patternId}`);
327
359
  }
328
360
  if (options.dryRun) {
329
- console.log(chalk.yellow('\n[DRY RUN] Would generate ESLint rules for above patterns'));
361
+ ui.warning('[DRY RUN] Would generate ESLint rules for above patterns');
330
362
  return;
331
363
  }
332
- // Generate ESLint rules
364
+ // Generate ESLint rules using runTasks
333
365
  const generator = new ESLintGenerator();
334
- const improvementResults = await generator.generateAllRules(patternsToImprove);
335
- console.log(chalk.blue('\n📋 Improvement Results:'));
336
- for (const result of improvementResults) {
337
- if (result.success) {
338
- console.log(chalk.green(` ✓ ${result.action}: ${result.filePath}`));
339
- }
340
- else {
341
- console.log(chalk.red(` ✗ ${result.action}: ${result.error}`));
342
- }
343
- }
344
- const successCount = improvementResults.filter(r => r.success).length;
345
- console.log(chalk.green(`\n✅ Completed: ${successCount}/${improvementResults.length} improvements`));
366
+ const tasks = patternsToImprove.map(pattern => ({
367
+ name: `Generate rule for ${pattern.patternId}`,
368
+ task: async () => generator.generateRule(pattern),
369
+ }));
370
+ await runTasks(tasks, { stopOnError: false });
346
371
  });
347
372
  // =============================================================================
348
373
  // STATUS COMMAND
@@ -351,20 +376,22 @@ program
351
376
  .command('status')
352
377
  .description('Show memory system status')
353
378
  .action(async () => {
354
- console.log(chalk.blue('📊 Memory System Status\n'));
379
+ ui.header('Memory System Status');
355
380
  const projectRoot = await getProjectRoot();
356
381
  // Check config
357
382
  let config;
358
383
  try {
359
384
  config = await loadConfig(projectRoot);
360
- console.log(chalk.green('Configuration found'));
361
- console.log(` System: ${config.system}`);
362
- console.log(` Project: ${config.projectName}`);
363
- console.log(` Domains: ${config.domains.length}`);
385
+ ui.success('Configuration found');
386
+ ui.keyValue({
387
+ 'System': config.system,
388
+ 'Project': config.projectName,
389
+ 'Domains': config.domains.length,
390
+ });
364
391
  }
365
392
  catch {
366
- console.log(chalk.red('No configuration found'));
367
- console.log(chalk.gray(' Run: claude-memory init'));
393
+ ui.error('No configuration found');
394
+ ui.dim('Run: cmp-standards init');
368
395
  return;
369
396
  }
370
397
  // Check registry
@@ -372,23 +399,25 @@ program
372
399
  try {
373
400
  const registryContent = await fs.readFile(registryPath, 'utf-8');
374
401
  const registry = JSON.parse(registryContent);
375
- console.log(chalk.green('Registry found'));
376
- console.log(` Sections: ${registry.sections.length}`);
377
- console.log(` Generated: ${registry.generatedAt || 'pending'}`);
402
+ ui.success('Registry found');
403
+ ui.keyValue({
404
+ 'Sections': registry.sections.length,
405
+ 'Generated': registry.generatedAt || 'pending',
406
+ });
378
407
  }
379
408
  catch {
380
- console.log(chalk.yellow('No registry found'));
381
- console.log(chalk.gray(' Run: claude-memory generate'));
409
+ ui.warning('No registry found');
410
+ ui.dim('Run: cmp-standards generate');
382
411
  }
383
412
  // Check hooks
384
413
  const hooksDir = getHooksDir(projectRoot);
385
414
  try {
386
415
  const hooks = await fs.readdir(hooksDir);
387
416
  const hookFiles = hooks.filter(h => h.endsWith('.ts') || h.endsWith('.md'));
388
- console.log(chalk.green(`✓ Hooks directory (${hookFiles.length} files)`));
417
+ ui.success(`Hooks directory (${hookFiles.length} files)`);
389
418
  }
390
419
  catch {
391
- console.log(chalk.yellow('No hooks directory'));
420
+ ui.warning('No hooks directory');
392
421
  }
393
422
  // Check settings.json
394
423
  const settingsPath = path.join(projectRoot, '.claude/settings.json');
@@ -397,21 +426,23 @@ program
397
426
  const settings = JSON.parse(settingsContent);
398
427
  const hasMemoryPlugin = settings.plugins?.['metanautical-memory'];
399
428
  if (hasMemoryPlugin) {
400
- console.log(chalk.green('Memory plugin configured in settings.json'));
429
+ ui.success('Memory plugin configured in settings.json');
401
430
  }
402
431
  else {
403
- console.log(chalk.yellow('Memory plugin not in settings.json'));
432
+ ui.warning('Memory plugin not in settings.json');
404
433
  }
405
434
  }
406
435
  catch {
407
- console.log(chalk.yellow('No settings.json found'));
436
+ ui.warning('No settings.json found');
408
437
  }
409
438
  // Features status
410
- console.log(chalk.blue('\n🔧 Features:'));
411
- console.log(` Guards: ${config.guards.enabled ? 'Enabled' : 'Disabled'} (${config.guards.rules.length} rules)`);
412
- console.log(` Embedding: ${config.embedding.enabled ? 'Enabled' : 'Disabled'}`);
413
- console.log(` Checkpoint: ${config.checkpoint.enabled ? 'Enabled' : 'Disabled'}`);
414
- console.log(` Auto-improve: ${config.autoImprovement.enabled ? 'Enabled' : 'Disabled'} (threshold: ${config.autoImprovement.violationThreshold})`);
439
+ ui.subheader('Features');
440
+ ui.keyValue({
441
+ 'Guards': `${config.guards.enabled ? 'Enabled' : 'Disabled'} (${config.guards.rules.length} rules)`,
442
+ 'Embedding': config.embedding.enabled ? 'Enabled' : 'Disabled',
443
+ 'Checkpoint': config.checkpoint.enabled ? 'Enabled' : 'Disabled',
444
+ 'Auto-improve': `${config.autoImprovement.enabled ? 'Enabled' : 'Disabled'} (threshold: ${config.autoImprovement.violationThreshold})`,
445
+ });
415
446
  });
416
447
  // =============================================================================
417
448
  // DASHBOARD COMMAND
@@ -518,6 +549,81 @@ program
518
549
  console.log(chalk.gray(`\nGenerated at: ${report.generatedAt}`));
519
550
  });
520
551
  // =============================================================================
552
+ // CROSS-PROJECT ANALYTICS COMMAND
553
+ // =============================================================================
554
+ program
555
+ .command('cross-analytics')
556
+ .description('Show cross-project analytics and insights')
557
+ .option('--json', 'Output as JSON')
558
+ .option('-d, --days <days>', 'Number of days to analyze', '30')
559
+ .action(async (options) => {
560
+ ui.header('Cross-Project Analytics');
561
+ const { getCrossProjectAnalytics } = await import('../analytics/CrossProjectAnalytics.js');
562
+ const analytics = getCrossProjectAnalytics();
563
+ const report = await withSpinner('Generating cross-project report', async () => {
564
+ return analytics.generateReport({
565
+ startDate: new Date(Date.now() - parseInt(options.days) * 24 * 60 * 60 * 1000),
566
+ });
567
+ });
568
+ if (options.json) {
569
+ console.log(JSON.stringify(report, null, 2));
570
+ return;
571
+ }
572
+ // Total Metrics
573
+ ui.subheader('Ecosystem Overview');
574
+ ui.keyValue({
575
+ 'Total Projects': report.totalMetrics.totalProjects,
576
+ 'Total Memories': report.totalMetrics.totalMemories,
577
+ 'Total Tasks': report.totalMetrics.totalTasks,
578
+ 'Total Sessions': report.totalMetrics.totalSessions,
579
+ 'Avg Health Score': `${report.totalMetrics.avgHealthScore.toFixed(0)}%`,
580
+ });
581
+ // Project Metrics
582
+ if (report.projectMetrics.length > 0) {
583
+ ui.subheader('Project Health');
584
+ for (const project of report.projectMetrics) {
585
+ const healthIcon = project.healthScore >= 70 ? '🟢' : project.healthScore >= 40 ? '🟡' : '🔴';
586
+ console.log(` ${healthIcon} ${project.system}: ${project.healthScore}% (${project.memories} memories, ${project.sessions} sessions)`);
587
+ }
588
+ }
589
+ // Insights
590
+ if (report.insights.length > 0) {
591
+ ui.subheader('Insights');
592
+ for (const insight of report.insights.slice(0, 5)) {
593
+ const icon = insight.type === 'warning' ? '⚠️' : insight.type === 'best_practice' ? '✨' : '💡';
594
+ const priority = insight.priority === 'high' ? chalk.red(`[${insight.priority}]`) : chalk.gray(`[${insight.priority}]`);
595
+ console.log(` ${icon} ${priority} ${insight.title}`);
596
+ if (insight.suggestedAction) {
597
+ ui.dim(` → ${insight.suggestedAction}`);
598
+ }
599
+ }
600
+ }
601
+ // Pattern Comparisons
602
+ if (report.patternComparisons.length > 0) {
603
+ ui.subheader('Shared Patterns');
604
+ for (const pattern of report.patternComparisons.slice(0, 5)) {
605
+ const systems = Object.keys(pattern.occurrences).length;
606
+ console.log(` 📊 ${pattern.patternId}: ${pattern.totalOccurrences}x across ${systems} projects`);
607
+ }
608
+ }
609
+ // Learning Opportunities
610
+ if (report.learningOpportunities.length > 0) {
611
+ ui.subheader('Learning Transfer Opportunities');
612
+ for (const opp of report.learningOpportunities.slice(0, 5)) {
613
+ console.log(` 🔄 "${opp.memoryTitle}" (${opp.fromSystem} → ${opp.toSystem})`);
614
+ ui.dim(` Relevance: ${(opp.relevanceScore * 100).toFixed(0)}%`);
615
+ }
616
+ }
617
+ // Recommendations
618
+ if (report.recommendations.length > 0) {
619
+ ui.subheader('Recommendations');
620
+ for (const rec of report.recommendations) {
621
+ console.log(` ➤ ${rec}`);
622
+ }
623
+ }
624
+ ui.dim(`\nReport generated: ${report.generatedAt}`);
625
+ });
626
+ // =============================================================================
521
627
  // FEEDBACK COMMAND
522
628
  // =============================================================================
523
629
  program
@@ -769,24 +875,24 @@ cloudCmd
769
875
  .command('status')
770
876
  .description('Check cloud services status')
771
877
  .action(async () => {
772
- console.log(chalk.blue('☁️ Cloud Services Status\n'));
773
- const { initCloud, healthCheck } = await import('../db/cloud.js');
774
- try {
775
- const status = await initCloud();
776
- console.log(`Turso: ${status.turso.ok ? chalk.green('✅') : chalk.red('❌')} ${status.turso.message}`);
777
- console.log(`Redis: ${status.redis.ok ? chalk.green('✅') : chalk.red('❌')} ${status.redis.message}`);
778
- console.log(`Vector: ${status.vector.ok ? chalk.green('✅') : chalk.red('❌')} ${status.vector.message}`);
779
- const allOk = status.turso.ok && status.redis.ok;
780
- if (allOk) {
781
- console.log(chalk.green('\nAll core services connected!'));
782
- }
783
- else {
784
- console.log(chalk.yellow('\n⚠️ Some services unavailable'));
785
- console.log(chalk.gray('Check your .env file for credentials'));
786
- }
878
+ ui.header('Cloud Services Status');
879
+ const { initCloud } = await import('../db/cloud.js');
880
+ const status = await withSpinner('Connecting to cloud services', async () => {
881
+ return initCloud();
882
+ });
883
+ ui.subheader('Service Status');
884
+ ui.keyValue({
885
+ 'Turso': `${status.turso.ok ? '✅' : '❌'} ${status.turso.message}`,
886
+ 'Redis': `${status.redis.ok ? '✅' : '❌'} ${status.redis.message}`,
887
+ 'Vector': `${status.vector.ok ? '✅' : '❌'} ${status.vector.message}`,
888
+ });
889
+ const allOk = status.turso.ok && status.redis.ok;
890
+ if (allOk) {
891
+ ui.success('All core services connected!');
787
892
  }
788
- catch (error) {
789
- console.log(chalk.red(`❌ Error: ${error}`));
893
+ else {
894
+ ui.warning('Some services unavailable');
895
+ ui.dim('Check your .env file for credentials');
790
896
  }
791
897
  });
792
898
  cloudCmd
@@ -995,6 +1101,417 @@ cloudCmd
995
1101
  }
996
1102
  });
997
1103
  // =============================================================================
1104
+ // QUICKSTART WIZARD
1105
+ // =============================================================================
1106
+ program
1107
+ .command('quickstart')
1108
+ .description('Interactive setup wizard for new projects')
1109
+ .action(async () => {
1110
+ console.log(chalk.blue(`
1111
+ ╔═══════════════════════════════════════════════════════════════╗
1112
+ ║ ║
1113
+ ║ 🚀 CMP-Standards Quickstart Wizard ║
1114
+ ║ ║
1115
+ ║ Set up your project in minutes with guided configuration ║
1116
+ ║ ║
1117
+ ╚═══════════════════════════════════════════════════════════════╝
1118
+ `));
1119
+ const inquirer = (await import('inquirer')).default;
1120
+ const projectRoot = await getProjectRoot();
1121
+ // Step 1: Check existing setup
1122
+ ui.header('Step 1: Checking Existing Setup');
1123
+ const existingConfig = await loadConfig(projectRoot).catch(() => null);
1124
+ if (existingConfig) {
1125
+ console.log(chalk.green(` ✓ Existing configuration found: ${existingConfig.system}`));
1126
+ const { continueSetup } = await inquirer.prompt([{
1127
+ type: 'confirm',
1128
+ name: 'continueSetup',
1129
+ message: 'Do you want to reconfigure?',
1130
+ default: false
1131
+ }]);
1132
+ if (!continueSetup) {
1133
+ console.log(chalk.gray('\n Run `cmp-standards status` to view current setup'));
1134
+ return;
1135
+ }
1136
+ }
1137
+ // Step 2: Project Configuration
1138
+ ui.header('Step 2: Project Configuration');
1139
+ const { system, projectName } = await inquirer.prompt([
1140
+ {
1141
+ type: 'input',
1142
+ name: 'system',
1143
+ message: 'System identifier (e.g., MYAPP, PANEL):',
1144
+ default: path.basename(projectRoot).toUpperCase().replace(/[^A-Z0-9]/g, '_'),
1145
+ validate: (input) => /^[A-Z][A-Z0-9_]*$/.test(input) || 'Must start with letter, use A-Z, 0-9, _'
1146
+ },
1147
+ {
1148
+ type: 'input',
1149
+ name: 'projectName',
1150
+ message: 'Project name:',
1151
+ default: path.basename(projectRoot)
1152
+ }
1153
+ ]);
1154
+ // Step 3: Cloud Services
1155
+ ui.header('Step 3: Cloud Services');
1156
+ const { hasCloudCredentials } = await import('../utils/env-loader.js');
1157
+ const creds = hasCloudCredentials();
1158
+ console.log(' Current status:');
1159
+ console.log(` Turso: ${creds.turso ? chalk.green('✓ Configured') : chalk.yellow('✗ Not configured')}`);
1160
+ console.log(` Redis: ${creds.redis ? chalk.green('✓ Configured') : chalk.yellow('✗ Not configured')}`);
1161
+ console.log(` Vector: ${creds.vector ? chalk.green('✓ Configured') : chalk.gray('○ Optional')}`);
1162
+ if (!creds.turso || !creds.redis) {
1163
+ const { setupCloud } = await inquirer.prompt([{
1164
+ type: 'confirm',
1165
+ name: 'setupCloud',
1166
+ message: 'Would you like guidance for setting up cloud services?',
1167
+ default: true
1168
+ }]);
1169
+ if (setupCloud) {
1170
+ console.log(chalk.cyan('\n 📚 Cloud Setup Guide:'));
1171
+ console.log(chalk.gray(' ─'.repeat(30)));
1172
+ if (!creds.turso) {
1173
+ console.log(chalk.yellow('\n Turso (SQLite Edge Database):'));
1174
+ console.log(' 1. Visit: https://turso.tech');
1175
+ console.log(' 2. Create free account');
1176
+ console.log(' 3. Create database named "memory"');
1177
+ console.log(' 4. Get URL: turso db show memory --url');
1178
+ console.log(' 5. Get token: turso db tokens create memory');
1179
+ console.log(chalk.gray(' Add to .env: TURSO_DATABASE_URL and TURSO_AUTH_TOKEN'));
1180
+ }
1181
+ if (!creds.redis) {
1182
+ console.log(chalk.yellow('\n Upstash Redis:'));
1183
+ console.log(' 1. Visit: https://console.upstash.com');
1184
+ console.log(' 2. Create Redis database');
1185
+ console.log(' 3. Copy REST credentials');
1186
+ console.log(chalk.gray(' Add to .env: UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN'));
1187
+ }
1188
+ const { hasCredentials } = await inquirer.prompt([{
1189
+ type: 'confirm',
1190
+ name: 'hasCredentials',
1191
+ message: 'Have you added the credentials to your .env file?',
1192
+ default: false
1193
+ }]);
1194
+ if (!hasCredentials) {
1195
+ console.log(chalk.gray('\n You can continue without cloud services (local mode)'));
1196
+ console.log(chalk.gray(' Run `cmp-standards cloud init` later to complete setup'));
1197
+ }
1198
+ }
1199
+ }
1200
+ // Step 4: Initialize Project
1201
+ ui.header('Step 4: Initializing Project');
1202
+ const { createProjectScaffold } = await import('../services/ProjectScaffold.js');
1203
+ const scaffold = createProjectScaffold(projectRoot);
1204
+ await scaffold.scaffold({
1205
+ system,
1206
+ projectName,
1207
+ force: true,
1208
+ skipAgents: false,
1209
+ skipHooks: false,
1210
+ skipCommands: false,
1211
+ });
1212
+ // Step 5: Verify Setup
1213
+ ui.header('Step 5: Verifying Setup');
1214
+ const { HookVerifierService } = await import('../services/HookVerifier.js');
1215
+ const verifier = new HookVerifierService(projectRoot);
1216
+ const report = await verifier.verify(true); // Auto-fix
1217
+ console.log(` Hooks verified: ${report.results.filter(r => r.status === 'valid').length}/${report.results.length}`);
1218
+ // Summary
1219
+ console.log(chalk.green(`
1220
+ ╔═══════════════════════════════════════════════════════════════╗
1221
+ ║ ║
1222
+ ║ ✅ Setup Complete! ║
1223
+ ║ ║
1224
+ ╚═══════════════════════════════════════════════════════════════╝
1225
+ `));
1226
+ console.log(` System: ${chalk.cyan(system)}`);
1227
+ console.log(` Project: ${projectName}`);
1228
+ console.log('');
1229
+ console.log(' Next steps:');
1230
+ console.log(` ${chalk.yellow('cmp-standards status')} - Check system status`);
1231
+ console.log(` ${chalk.yellow('cmp-standards validate')} - Validate project structure`);
1232
+ console.log(` ${chalk.yellow('/experts src/')} - Run code review`);
1233
+ console.log('');
1234
+ });
1235
+ // =============================================================================
1236
+ // DOCTOR COMMAND
1237
+ // =============================================================================
1238
+ program
1239
+ .command('doctor')
1240
+ .description('Diagnose and fix common issues')
1241
+ .option('--fix', 'Attempt to fix issues automatically')
1242
+ .option('--json', 'Output as JSON')
1243
+ .action(async (options) => {
1244
+ ui.header('CMP-Standards Doctor');
1245
+ const projectRoot = await getProjectRoot();
1246
+ const issues = [];
1247
+ // Check 1: Configuration
1248
+ console.log(chalk.gray(' Checking configuration...'));
1249
+ let config = null;
1250
+ try {
1251
+ config = await loadConfig(projectRoot);
1252
+ }
1253
+ catch {
1254
+ issues.push({
1255
+ category: 'config',
1256
+ severity: 'error',
1257
+ message: 'No memory-config.json found',
1258
+ fix: 'Run: cmp-standards init --system YOUR_SYSTEM',
1259
+ fixable: false
1260
+ });
1261
+ }
1262
+ // Check 2: Required directories
1263
+ console.log(chalk.gray(' Checking directory structure...'));
1264
+ const requiredDirs = ['.claude', '.claude/agents', '.claude/commands', '.claude/hooks'];
1265
+ for (const dir of requiredDirs) {
1266
+ const dirPath = path.join(projectRoot, dir);
1267
+ try {
1268
+ await fs.access(dirPath);
1269
+ }
1270
+ catch {
1271
+ issues.push({
1272
+ category: 'structure',
1273
+ severity: 'error',
1274
+ message: `Missing directory: ${dir}`,
1275
+ fix: `mkdir -p ${dir}`,
1276
+ fixable: true
1277
+ });
1278
+ if (options.fix) {
1279
+ await fs.mkdir(dirPath, { recursive: true });
1280
+ }
1281
+ }
1282
+ }
1283
+ // Check 3: Required files
1284
+ console.log(chalk.gray(' Checking required files...'));
1285
+ const requiredFiles = ['CLAUDE.md', '.claude/settings.json'];
1286
+ for (const file of requiredFiles) {
1287
+ const filePath = path.join(projectRoot, file);
1288
+ try {
1289
+ await fs.access(filePath);
1290
+ }
1291
+ catch {
1292
+ issues.push({
1293
+ category: 'structure',
1294
+ severity: 'error',
1295
+ message: `Missing file: ${file}`,
1296
+ fix: 'Run: cmp-standards init --system YOUR_SYSTEM',
1297
+ fixable: false
1298
+ });
1299
+ }
1300
+ }
1301
+ // Check 4: Cloud credentials
1302
+ console.log(chalk.gray(' Checking cloud credentials...'));
1303
+ const { hasCloudCredentials } = await import('../utils/env-loader.js');
1304
+ const creds = hasCloudCredentials();
1305
+ if (!creds.turso) {
1306
+ issues.push({
1307
+ category: 'cloud',
1308
+ severity: 'warning',
1309
+ message: 'Turso credentials not configured',
1310
+ fix: 'Run: cmp-standards cloud init',
1311
+ fixable: false
1312
+ });
1313
+ }
1314
+ if (!creds.redis) {
1315
+ issues.push({
1316
+ category: 'cloud',
1317
+ severity: 'warning',
1318
+ message: 'Upstash Redis credentials not configured',
1319
+ fix: 'Run: cmp-standards cloud init',
1320
+ fixable: false
1321
+ });
1322
+ }
1323
+ // Check 5: Hook configurations
1324
+ console.log(chalk.gray(' Checking hooks...'));
1325
+ try {
1326
+ const { HookVerifierService } = await import('../services/HookVerifier.js');
1327
+ const verifier = new HookVerifierService(projectRoot);
1328
+ const report = await verifier.verify(options.fix);
1329
+ for (const result of report.results) {
1330
+ if (result.status !== 'valid') {
1331
+ const isError = result.status === 'missing_file' || result.status === 'invalid_syntax';
1332
+ issues.push({
1333
+ category: 'hooks',
1334
+ severity: isError ? 'error' : 'warning',
1335
+ message: `Hook ${result.hookPath}: ${result.message}`,
1336
+ fix: result.autoFixable ? (options.fix && result.fixed ? 'Fixed automatically' : 'Run with --fix') : undefined,
1337
+ fixable: result.autoFixable
1338
+ });
1339
+ }
1340
+ }
1341
+ }
1342
+ catch {
1343
+ // No hooks to check
1344
+ }
1345
+ // Check 6: Node version
1346
+ console.log(chalk.gray(' Checking Node.js version...'));
1347
+ const nodeVersion = process.version.match(/^v(\d+)/)?.[1];
1348
+ if (nodeVersion && parseInt(nodeVersion) < 18) {
1349
+ issues.push({
1350
+ category: 'environment',
1351
+ severity: 'error',
1352
+ message: `Node.js ${process.version} is not supported (requires >=18)`,
1353
+ fixable: false
1354
+ });
1355
+ }
1356
+ // Output results
1357
+ if (options.json) {
1358
+ console.log(JSON.stringify({ issues, summary: {
1359
+ total: issues.length,
1360
+ errors: issues.filter(i => i.severity === 'error').length,
1361
+ warnings: issues.filter(i => i.severity === 'warning').length,
1362
+ info: issues.filter(i => i.severity === 'info').length
1363
+ } }, null, 2));
1364
+ return;
1365
+ }
1366
+ console.log('');
1367
+ if (issues.length === 0) {
1368
+ console.log(chalk.green(' ✅ No issues found! Your setup looks healthy.'));
1369
+ }
1370
+ else {
1371
+ const errors = issues.filter(i => i.severity === 'error');
1372
+ const warnings = issues.filter(i => i.severity === 'warning');
1373
+ if (errors.length > 0) {
1374
+ ui.subheader(`Errors (${errors.length})`);
1375
+ for (const issue of errors) {
1376
+ console.log(` ❌ [${issue.category}] ${issue.message}`);
1377
+ if (issue.fix) {
1378
+ console.log(chalk.gray(` Fix: ${issue.fix}`));
1379
+ }
1380
+ }
1381
+ }
1382
+ if (warnings.length > 0) {
1383
+ ui.subheader(`Warnings (${warnings.length})`);
1384
+ for (const issue of warnings) {
1385
+ console.log(` ⚠️ [${issue.category}] ${issue.message}`);
1386
+ if (issue.fix) {
1387
+ console.log(chalk.gray(` Fix: ${issue.fix}`));
1388
+ }
1389
+ }
1390
+ }
1391
+ const fixable = issues.filter(i => i.fixable && i.severity === 'error');
1392
+ if (fixable.length > 0 && !options.fix) {
1393
+ console.log(chalk.yellow(`\n 💡 ${fixable.length} issues can be fixed automatically.`));
1394
+ console.log(chalk.yellow(' Run: cmp-standards doctor --fix'));
1395
+ }
1396
+ }
1397
+ });
1398
+ // =============================================================================
1399
+ // COMPLETION COMMAND
1400
+ // =============================================================================
1401
+ program
1402
+ .command('completion')
1403
+ .description('Generate shell completion scripts')
1404
+ .argument('<shell>', 'Shell type: bash, zsh, fish, powershell')
1405
+ .action(async (shell) => {
1406
+ const commands = [
1407
+ 'init', 'sync', 'validate', 'verify-hooks', 'generate', 'scan', 'improve',
1408
+ 'status', 'dashboard', 'mcp', 'analytics', 'cross-analytics', 'feedback',
1409
+ 'tasks', 'ideas', 'improvements', 'plan', 'capture', 'export',
1410
+ 'cloud', 'quickstart', 'doctor', 'completion'
1411
+ ];
1412
+ const subcommands = {
1413
+ cloud: ['status', 'init', 'improvements', 'tasks', 'session']
1414
+ };
1415
+ switch (shell.toLowerCase()) {
1416
+ case 'bash':
1417
+ console.log(`# CMP-Standards Bash Completion
1418
+ # Add to ~/.bashrc or ~/.bash_profile:
1419
+ # source <(cmp-standards completion bash)
1420
+
1421
+ _cmp_standards_completions() {
1422
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
1423
+ local prev="\${COMP_WORDS[COMP_CWORD-1]}"
1424
+
1425
+ case "\${prev}" in
1426
+ cmp-standards)
1427
+ COMPREPLY=( $(compgen -W "${commands.join(' ')}" -- "\${cur}") )
1428
+ return 0
1429
+ ;;
1430
+ cloud)
1431
+ COMPREPLY=( $(compgen -W "${subcommands.cloud.join(' ')}" -- "\${cur}") )
1432
+ return 0
1433
+ ;;
1434
+ esac
1435
+ }
1436
+
1437
+ complete -F _cmp_standards_completions cmp-standards
1438
+ `);
1439
+ break;
1440
+ case 'zsh':
1441
+ console.log(`# CMP-Standards Zsh Completion
1442
+ # Add to ~/.zshrc:
1443
+ # source <(cmp-standards completion zsh)
1444
+
1445
+ _cmp_standards() {
1446
+ local -a commands
1447
+ commands=(
1448
+ ${commands.map(c => `'${c}:${c} command'`).join('\n ')}
1449
+ )
1450
+
1451
+ local -a cloud_subcommands
1452
+ cloud_subcommands=(
1453
+ ${subcommands.cloud.map(c => `'${c}:cloud ${c}'`).join('\n ')}
1454
+ )
1455
+
1456
+ _arguments -C \\
1457
+ '1: :->command' \\
1458
+ '*:: :->args'
1459
+
1460
+ case $state in
1461
+ command)
1462
+ _describe -t commands 'cmp-standards commands' commands
1463
+ ;;
1464
+ args)
1465
+ case $words[1] in
1466
+ cloud)
1467
+ _describe -t commands 'cloud subcommands' cloud_subcommands
1468
+ ;;
1469
+ esac
1470
+ ;;
1471
+ esac
1472
+ }
1473
+
1474
+ compdef _cmp_standards cmp-standards
1475
+ `);
1476
+ break;
1477
+ case 'fish':
1478
+ console.log(`# CMP-Standards Fish Completion
1479
+ # Add to ~/.config/fish/completions/cmp-standards.fish
1480
+
1481
+ ${commands.map(c => `complete -c cmp-standards -f -n "__fish_use_subcommand" -a ${c} -d "${c}"`).join('\n')}
1482
+ ${subcommands.cloud.map(c => `complete -c cmp-standards -f -n "__fish_seen_subcommand_from cloud" -a ${c} -d "cloud ${c}"`).join('\n')}
1483
+ `);
1484
+ break;
1485
+ case 'powershell':
1486
+ console.log(`# CMP-Standards PowerShell Completion
1487
+ # Add to $PROFILE:
1488
+
1489
+ Register-ArgumentCompleter -CommandName cmp-standards -ScriptBlock {
1490
+ param($wordToComplete, $commandAst, $cursorPosition)
1491
+
1492
+ $commands = @(${commands.map(c => `'${c}'`).join(', ')})
1493
+
1494
+ if ($commandAst.CommandElements.Count -eq 2) {
1495
+ $commands | Where-Object { $_ -like "$wordToComplete*" } |
1496
+ ForEach-Object {
1497
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
1498
+ }
1499
+ } elseif ($commandAst.CommandElements[1].Extent.Text -eq 'cloud') {
1500
+ @(${subcommands.cloud.map(c => `'${c}'`).join(', ')}) | Where-Object { $_ -like "$wordToComplete*" } |
1501
+ ForEach-Object {
1502
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
1503
+ }
1504
+ }
1505
+ }
1506
+ `);
1507
+ break;
1508
+ default:
1509
+ console.error(chalk.red(`Unknown shell: ${shell}`));
1510
+ console.log('Supported shells: bash, zsh, fish, powershell');
1511
+ process.exit(1);
1512
+ }
1513
+ });
1514
+ // =============================================================================
998
1515
  // MAIN
999
1516
  // =============================================================================
1000
1517
  program.parse();