cmp-standards 2.8.1 ā 2.9.1
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.
- package/dist/analytics/CrossProjectAnalytics.d.ts +128 -0
- package/dist/analytics/CrossProjectAnalytics.d.ts.map +1 -0
- package/dist/analytics/CrossProjectAnalytics.js +431 -0
- package/dist/analytics/CrossProjectAnalytics.js.map +1 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/analytics/index.js +2 -0
- package/dist/analytics/index.js.map +1 -1
- package/dist/cache/EmbeddingCache.d.ts +6 -4
- package/dist/cache/EmbeddingCache.d.ts.map +1 -1
- package/dist/cache/EmbeddingCache.js +28 -17
- package/dist/cache/EmbeddingCache.js.map +1 -1
- package/dist/cli/index.js +247 -141
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ui.d.ts +134 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +311 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/dashboard/tokens.d.ts +228 -0
- package/dist/dashboard/tokens.d.ts.map +1 -0
- package/dist/dashboard/tokens.js +450 -0
- package/dist/dashboard/tokens.js.map +1 -0
- package/dist/dashboard/ui.d.ts +3 -0
- package/dist/dashboard/ui.d.ts.map +1 -1
- package/dist/dashboard/ui.js +95 -61
- package/dist/dashboard/ui.js.map +1 -1
- package/dist/db/cloud.d.ts +11 -0
- package/dist/db/cloud.d.ts.map +1 -1
- package/dist/db/cloud.js +49 -1
- package/dist/db/cloud.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +109 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/startup-verify.d.ts +31 -0
- package/dist/hooks/startup-verify.d.ts.map +1 -0
- package/dist/hooks/startup-verify.js +360 -0
- package/dist/hooks/startup-verify.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +160 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +417 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/services/AuditLog.d.ts +205 -0
- package/dist/services/AuditLog.d.ts.map +1 -0
- package/dist/services/AuditLog.js +352 -0
- package/dist/services/AuditLog.js.map +1 -0
- package/dist/services/FeedbackCollector.d.ts +8 -0
- package/dist/services/FeedbackCollector.d.ts.map +1 -1
- package/dist/services/FeedbackCollector.js +19 -2
- package/dist/services/FeedbackCollector.js.map +1 -1
- package/dist/services/GitIntegration.d.ts +140 -0
- package/dist/services/GitIntegration.d.ts.map +1 -0
- package/dist/services/GitIntegration.js +423 -0
- package/dist/services/GitIntegration.js.map +1 -0
- package/dist/services/HookVerifier.d.ts +95 -0
- package/dist/services/HookVerifier.d.ts.map +1 -0
- package/dist/services/HookVerifier.js +493 -0
- package/dist/services/HookVerifier.js.map +1 -0
- package/dist/services/MemoryVersioning.d.ts +108 -0
- package/dist/services/MemoryVersioning.d.ts.map +1 -0
- package/dist/services/MemoryVersioning.js +281 -0
- package/dist/services/MemoryVersioning.js.map +1 -0
- package/dist/services/context-injector.d.ts +8 -0
- package/dist/services/context-injector.d.ts.map +1 -1
- package/dist/services/context-injector.js +19 -2
- package/dist/services/context-injector.js.map +1 -1
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +5 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/memory-router.d.ts +8 -0
- package/dist/services/memory-router.d.ts.map +1 -1
- package/dist/services/memory-router.js +19 -2
- package/dist/services/memory-router.js.map +1 -1
- package/dist/services/pattern-tracker.d.ts +13 -0
- package/dist/services/pattern-tracker.d.ts.map +1 -1
- package/dist/services/pattern-tracker.js +33 -3
- package/dist/services/pattern-tracker.js.map +1 -1
- package/dist/services/semantic-search.d.ts +4 -0
- package/dist/services/semantic-search.d.ts.map +1 -1
- package/dist/services/semantic-search.js +53 -13
- package/dist/services/semantic-search.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +4 -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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
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
|
-
|
|
237
|
-
|
|
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
|
|
255
|
+
await withSpinner('Generating registry', async (spinner) => {
|
|
256
|
+
spinner.text = 'Scanning documentation...';
|
|
257
|
+
await generator.generate();
|
|
258
|
+
}, { successText: 'Registry generated' });
|
|
241
259
|
}
|
|
242
|
-
|
|
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
|
-
|
|
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
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
353
|
+
ui.success('No patterns need improvement');
|
|
322
354
|
return;
|
|
323
355
|
}
|
|
324
|
-
|
|
356
|
+
ui.info(`Found ${patternsToImprove.length} patterns to improve:`);
|
|
325
357
|
for (const pattern of patternsToImprove) {
|
|
326
|
-
|
|
358
|
+
ui.dim(` - ${pattern.patternId}`);
|
|
327
359
|
}
|
|
328
360
|
if (options.dryRun) {
|
|
329
|
-
|
|
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
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
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
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
367
|
-
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
381
|
-
|
|
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
|
-
|
|
417
|
+
ui.success(`Hooks directory (${hookFiles.length} files)`);
|
|
389
418
|
}
|
|
390
419
|
catch {
|
|
391
|
-
|
|
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
|
-
|
|
429
|
+
ui.success('Memory plugin configured in settings.json');
|
|
401
430
|
}
|
|
402
431
|
else {
|
|
403
|
-
|
|
432
|
+
ui.warning('Memory plugin not in settings.json');
|
|
404
433
|
}
|
|
405
434
|
}
|
|
406
435
|
catch {
|
|
407
|
-
|
|
436
|
+
ui.warning('No settings.json found');
|
|
408
437
|
}
|
|
409
438
|
// Features status
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
-
|
|
773
|
-
const { initCloud
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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
|
-
|
|
789
|
-
|
|
893
|
+
else {
|
|
894
|
+
ui.warning('Some services unavailable');
|
|
895
|
+
ui.dim('Check your .env file for credentials');
|
|
790
896
|
}
|
|
791
897
|
});
|
|
792
898
|
cloudCmd
|