@equilateral_ai/mindmeld 3.5.2 → 4.0.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.
Files changed (140) hide show
  1. package/hooks/session-end.js +25 -0
  2. package/hooks/session-start.js +363 -83
  3. package/hooks/session-watcher.js +585 -0
  4. package/package.json +19 -13
  5. package/scripts/init-project.js +9 -23
  6. package/src/client/dbShim.js +16 -0
  7. package/src/core/AuthManager.js +3 -2
  8. package/src/handlers/helpers/dbOperations.js +9 -46
  9. package/src/index.js +2 -217
  10. package/src/utils/piiMask.js +16 -0
  11. package/scripts/harvest.js +0 -601
  12. package/scripts/inject.js +0 -409
  13. package/scripts/mcp-bridge.js +0 -220
  14. package/scripts/repo-analyzer.js +0 -870
  15. package/src/collaboration/CollaborationPrompt.js +0 -460
  16. package/src/core/AlertEngine.js +0 -813
  17. package/src/core/AlertNotifier.js +0 -363
  18. package/src/core/CorrelationAnalyzer.js +0 -931
  19. package/src/core/CrossReferenceEngine.js +0 -624
  20. package/src/core/CurationEngine.js +0 -688
  21. package/src/core/DeprecationScheduler.js +0 -183
  22. package/src/core/LoadBearingDetector.js +0 -242
  23. package/src/core/NotificationService.js +0 -1032
  24. package/src/core/RapportOrchestrator.js +0 -632
  25. package/src/core/RelevanceDetector.js +0 -694
  26. package/src/core/StandardLifecycle.js +0 -244
  27. package/src/core/StandardsIngestion.js +0 -991
  28. package/src/core/TeamLoadBearingDetector.js +0 -431
  29. package/src/core/parsers/adrParser.js +0 -479
  30. package/src/core/parsers/cursorRulesParser.js +0 -564
  31. package/src/core/parsers/eslintParser.js +0 -439
  32. package/src/database/dbOperations.js +0 -105
  33. package/src/handlers/activity/activityGetMe.js +0 -98
  34. package/src/handlers/activity/activityGetTeam.js +0 -175
  35. package/src/handlers/admin/adminSetup.js +0 -216
  36. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  37. package/src/handlers/alerts/alertsGet.js +0 -250
  38. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  39. package/src/handlers/analytics/coachingGet.js +0 -361
  40. package/src/handlers/analytics/convergenceGet.js +0 -236
  41. package/src/handlers/analytics/developerScoreGet.js +0 -137
  42. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  43. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  44. package/src/handlers/collaborators/collaboratorList.js +0 -82
  45. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  46. package/src/handlers/collaborators/inviteAccept.js +0 -122
  47. package/src/handlers/company/companyUsersDelete.js +0 -141
  48. package/src/handlers/company/companyUsersGet.js +0 -90
  49. package/src/handlers/company/companyUsersPost.js +0 -267
  50. package/src/handlers/company/companyUsersPut.js +0 -76
  51. package/src/handlers/context/contextGet.js +0 -57
  52. package/src/handlers/context/invariantsGet.js +0 -74
  53. package/src/handlers/context/loopsGet.js +0 -82
  54. package/src/handlers/context/notesCreate.js +0 -74
  55. package/src/handlers/context/purposeGet.js +0 -78
  56. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  57. package/src/handlers/correlations/correlationsGet.js +0 -93
  58. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  59. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  60. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  61. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  62. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  63. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  64. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  65. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  66. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  67. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  68. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  69. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  70. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  71. package/src/handlers/github/githubConnectionStatus.js +0 -49
  72. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  73. package/src/handlers/github/githubOAuthCallback.js +0 -178
  74. package/src/handlers/github/githubOAuthStart.js +0 -59
  75. package/src/handlers/github/githubPatternsReview.js +0 -76
  76. package/src/handlers/github/githubReposList.js +0 -105
  77. package/src/handlers/health/healthGet.js +0 -55
  78. package/src/handlers/helpers/auditLogger.js +0 -201
  79. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  80. package/src/handlers/helpers/decisionFrames.js +0 -29
  81. package/src/handlers/helpers/errorHandler.js +0 -49
  82. package/src/handlers/helpers/index.js +0 -138
  83. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  84. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  85. package/src/handlers/helpers/predictiveCache.js +0 -51
  86. package/src/handlers/helpers/projectAccess.js +0 -88
  87. package/src/handlers/helpers/responseUtil.js +0 -55
  88. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  89. package/src/handlers/mcp/mcpHandler.js +0 -569
  90. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  91. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  92. package/src/handlers/notifications/getPreferences.js +0 -84
  93. package/src/handlers/notifications/sendNotification.js +0 -170
  94. package/src/handlers/notifications/updatePreferences.js +0 -316
  95. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  96. package/src/handlers/patterns/patternUsagePost.js +0 -182
  97. package/src/handlers/patterns/patternViolationPost.js +0 -185
  98. package/src/handlers/projects/projectCreate.js +0 -248
  99. package/src/handlers/projects/projectDelete.js +0 -82
  100. package/src/handlers/projects/projectGet.js +0 -95
  101. package/src/handlers/projects/projectUpdate.js +0 -117
  102. package/src/handlers/reports/aiLeverage.js +0 -210
  103. package/src/handlers/reports/engineeringInvestment.js +0 -132
  104. package/src/handlers/reports/riskForecast.js +0 -206
  105. package/src/handlers/reports/standardsRoi.js +0 -254
  106. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  107. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  108. package/src/handlers/scheduled/generateAlerts.js +0 -135
  109. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  110. package/src/handlers/scheduled/refreshActivity.js +0 -21
  111. package/src/handlers/scheduled/scanCompliance.js +0 -334
  112. package/src/handlers/sessions/sessionEndPost.js +0 -180
  113. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  114. package/src/handlers/standards/catalogGet.js +0 -185
  115. package/src/handlers/standards/catalogSync.js +0 -120
  116. package/src/handlers/standards/discoveriesGet.js +0 -89
  117. package/src/handlers/standards/projectStandardsGet.js +0 -129
  118. package/src/handlers/standards/projectStandardsPut.js +0 -151
  119. package/src/handlers/standards/standardsAuditGet.js +0 -65
  120. package/src/handlers/standards/standardsParseUpload.js +0 -149
  121. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  122. package/src/handlers/standards/standardsTransition.js +0 -161
  123. package/src/handlers/stripe/addonManagePost.js +0 -240
  124. package/src/handlers/stripe/billingPortalPost.js +0 -93
  125. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  126. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  127. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  128. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  129. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  130. package/src/handlers/stripe/webhookPost.js +0 -482
  131. package/src/handlers/user/apiTokenCreate.js +0 -71
  132. package/src/handlers/user/apiTokenList.js +0 -64
  133. package/src/handlers/user/userSplashAck.js +0 -91
  134. package/src/handlers/user/userSplashGet.js +0 -211
  135. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  136. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  137. package/src/handlers/users/userEntitlementsGet.js +0 -89
  138. package/src/handlers/users/userGet.js +0 -118
  139. package/src/handlers/users/userProfilePut.js +0 -77
  140. package/src/handlers/webhooks/githubWebhook.js +0 -215
@@ -1,694 +0,0 @@
1
- /**
2
- * RelevanceDetector - Phase 2: Rapport Standards Integration
3
- *
4
- * Identifies which standards apply to current work by:
5
- * 1. Detecting project characteristics (Lambda, React, SAM, etc.)
6
- * 2. Mapping characteristics to standard categories
7
- * 3. Querying relevant standards from database
8
- * 4. Returning top 10 most relevant standards with scoring
9
- *
10
- * Target: < 500ms execution time
11
- *
12
- * @module RelevanceDetector
13
- */
14
-
15
- const fs = require('fs').promises;
16
- const path = require('path');
17
- const { executeQuery } = require('../handlers/helpers/dbOperations');
18
- const { StandardsIngestion } = require('./StandardsIngestion');
19
-
20
- class RelevanceDetector {
21
- constructor(options = {}) {
22
- this.workingDirectory = options.workingDirectory || process.cwd();
23
- this.standardsPath = options.standardsPath || '.equilateral-standards';
24
-
25
- // Category weights for relevance scoring
26
- this.categoryWeights = {
27
- 'serverless-saas-aws': 1.0,
28
- 'multi-agent-orchestration': 1.0,
29
- 'frontend-development': 1.0,
30
- 'database': 0.9,
31
- 'compliance-security': 0.8,
32
- 'cost-optimization': 0.7,
33
- 'real-time-systems': 0.8,
34
- 'testing': 0.6,
35
- 'backend': 0.9,
36
- 'well-architected': 0.7
37
- };
38
- }
39
-
40
- /**
41
- * Main entry point: Detect relevant standards for current project context
42
- * @param {Object} projectContext - Context information about the project
43
- * @returns {Promise<Object>} Relevant standards with scoring
44
- */
45
- async detectRelevantStandards(projectContext = {}) {
46
- const startTime = Date.now();
47
-
48
- try {
49
- // 1. Analyze project structure to detect characteristics
50
- const characteristics = await this.detectProjectCharacteristics(projectContext);
51
-
52
- // 2. Map characteristics to standard categories
53
- const relevantCategories = this.mapCharacteristicsToCategories(characteristics);
54
-
55
- // 3. Query standards from database (assumes Phase 1 schema exists)
56
- const standards = await this.queryRelevantStandards({
57
- categories: relevantCategories,
58
- currentFile: projectContext.currentFile,
59
- characteristics: characteristics
60
- });
61
-
62
- // 4. Calculate relevance scores and rank
63
- const rankedStandards = this.rankStandards(standards, characteristics, relevantCategories);
64
-
65
- // 5. Return top 10 most relevant
66
- const topStandards = rankedStandards.slice(0, 10);
67
-
68
- const executionTime = Date.now() - startTime;
69
-
70
- return {
71
- characteristics,
72
- categories: relevantCategories,
73
- standards: topStandards,
74
- totalStandards: standards.length,
75
- executionTime,
76
- timestamp: new Date().toISOString()
77
- };
78
- } catch (error) {
79
- console.error('RelevanceDetector error:', error);
80
- throw error;
81
- }
82
- }
83
-
84
- /**
85
- * Detect project characteristics from file structure and content
86
- * Fast file system analysis without deep content parsing
87
- */
88
- async detectProjectCharacteristics(projectContext) {
89
- const characteristics = {
90
- hasLambda: false,
91
- hasReact: false,
92
- hasDatabase: false,
93
- hasMultiAgent: false,
94
- hasSAM: false,
95
- hasAPI: false,
96
- hasTypeScript: false,
97
- hasNodeJS: false,
98
- hasPython: false,
99
- hasDocker: false,
100
- hasCI: false,
101
- hasTests: false,
102
- framework: null,
103
- deploymentType: null
104
- };
105
-
106
- try {
107
- // Check for key files that indicate project type
108
- const keyFiles = await this.checkKeyFiles();
109
-
110
- // SAM/Serverless detection
111
- characteristics.hasSAM = keyFiles.includes('template.yaml') || keyFiles.includes('template.yml');
112
-
113
- // Lambda detection (SAM template or serverless.yml)
114
- if (characteristics.hasSAM || keyFiles.includes('serverless.yml')) {
115
- characteristics.hasLambda = await this.detectLambdaFunctions();
116
- }
117
-
118
- // React detection
119
- characteristics.hasReact = await this.detectReact(keyFiles);
120
-
121
- // Database detection
122
- characteristics.hasDatabase = await this.detectDatabase(keyFiles);
123
-
124
- // Multi-agent detection
125
- characteristics.hasMultiAgent = await this.detectMultiAgent();
126
-
127
- // API detection
128
- characteristics.hasAPI = await this.detectAPIHandlers();
129
-
130
- // Language detection
131
- characteristics.hasTypeScript = keyFiles.some(f => f.endsWith('.ts') || f.endsWith('.tsx'));
132
- characteristics.hasNodeJS = keyFiles.includes('package.json');
133
- characteristics.hasPython = keyFiles.includes('requirements.txt') || keyFiles.includes('setup.py');
134
-
135
- // Infrastructure detection
136
- characteristics.hasDocker = keyFiles.includes('Dockerfile') || keyFiles.includes('docker-compose.yml');
137
- characteristics.hasCI = keyFiles.includes('.github') || keyFiles.includes('.gitlab-ci.yml');
138
- characteristics.hasTests = keyFiles.includes('tests') || keyFiles.includes('test');
139
-
140
- // Determine framework
141
- characteristics.framework = await this.detectFramework(keyFiles);
142
-
143
- // Determine deployment type
144
- characteristics.deploymentType = this.determineDeploymentType(characteristics);
145
-
146
- return characteristics;
147
- } catch (error) {
148
- console.error('Error detecting characteristics:', error);
149
- return characteristics; // Return partial results
150
- }
151
- }
152
-
153
- /**
154
- * Check for key files in project
155
- */
156
- async checkKeyFiles() {
157
- try {
158
- const files = await fs.readdir(this.workingDirectory);
159
-
160
- // Also check common subdirectories
161
- const checkDirs = ['src', 'handlers', 'tests', 'test', '.github'];
162
- for (const dir of checkDirs) {
163
- try {
164
- const dirPath = path.join(this.workingDirectory, dir);
165
- const stats = await fs.stat(dirPath);
166
- if (stats.isDirectory()) {
167
- files.push(dir);
168
- }
169
- } catch (e) {
170
- // Directory doesn't exist, skip
171
- }
172
- }
173
-
174
- return files;
175
- } catch (error) {
176
- console.error('Error reading directory:', error);
177
- return [];
178
- }
179
- }
180
-
181
- /**
182
- * Detect Lambda functions by checking for handler files or SAM config
183
- */
184
- async detectLambdaFunctions() {
185
- try {
186
- // Check for SAM template with Lambda functions
187
- const templatePath = path.join(this.workingDirectory, 'template.yaml');
188
- try {
189
- const content = await fs.readFile(templatePath, 'utf-8');
190
- return content.includes('AWS::Serverless::Function') ||
191
- content.includes('AWS::Lambda::Function');
192
- } catch (e) {
193
- // File doesn't exist, check for handler files
194
- }
195
-
196
- // Check for common Lambda handler directories
197
- const handlerDirs = ['src/handlers', 'handlers', 'functions', 'lambdas'];
198
- for (const dir of handlerDirs) {
199
- try {
200
- const dirPath = path.join(this.workingDirectory, dir);
201
- await fs.access(dirPath);
202
- return true; // Directory exists
203
- } catch (e) {
204
- continue;
205
- }
206
- }
207
-
208
- return false;
209
- } catch (error) {
210
- return false;
211
- }
212
- }
213
-
214
- /**
215
- * Detect React usage
216
- */
217
- async detectReact(keyFiles) {
218
- // Check root package.json first
219
- try {
220
- const pkgPath = path.join(this.workingDirectory, 'package.json');
221
- const content = await fs.readFile(pkgPath, 'utf-8');
222
- const pkg = JSON.parse(content);
223
- if (pkg.dependencies?.react || pkg.devDependencies?.react) return true;
224
- } catch (error) { /* continue */ }
225
-
226
- // Check subdirectory package.json files (monorepo support)
227
- const subDirs = ['frontend', 'frontend/admin', 'client', 'web', 'app'];
228
- for (const dir of subDirs) {
229
- try {
230
- const pkgPath = path.join(this.workingDirectory, dir, 'package.json');
231
- const content = await fs.readFile(pkgPath, 'utf-8');
232
- const pkg = JSON.parse(content);
233
- if (pkg.dependencies?.react || pkg.devDependencies?.react) return true;
234
- } catch (error) { /* continue */ }
235
- }
236
-
237
- // Fallback: check for .jsx or .tsx files in keyFiles
238
- return keyFiles.some(f => f.endsWith('.jsx') || f.endsWith('.tsx'));
239
- }
240
-
241
- /**
242
- * Detect database usage
243
- */
244
- async detectDatabase(keyFiles) {
245
- // Check for database configuration files
246
- if (keyFiles.includes('schema.sql') ||
247
- keyFiles.includes('database') ||
248
- keyFiles.some(f => f.includes('migration'))) {
249
- return true;
250
- }
251
-
252
- // Check package.json for database libraries
253
- if (keyFiles.includes('package.json')) {
254
- try {
255
- const pkgPath = path.join(this.workingDirectory, 'package.json');
256
- const content = await fs.readFile(pkgPath, 'utf-8');
257
- const pkg = JSON.parse(content);
258
-
259
- const dbLibs = ['pg', 'mysql', 'mongodb', 'mongoose', 'sequelize', 'typeorm'];
260
- return dbLibs.some(lib =>
261
- pkg.dependencies?.[lib] || pkg.devDependencies?.[lib]
262
- );
263
- } catch (error) {
264
- return false;
265
- }
266
- }
267
-
268
- return false;
269
- }
270
-
271
- /**
272
- * Detect multi-agent orchestration patterns
273
- */
274
- async detectMultiAgent() {
275
- try {
276
- // Check for agent-related directories
277
- const agentDirs = ['agents', 'src/agents', 'src/core'];
278
- for (const dir of agentDirs) {
279
- try {
280
- const dirPath = path.join(this.workingDirectory, dir);
281
- const files = await fs.readdir(dirPath);
282
-
283
- // Look for agent-related files
284
- if (files.some(f =>
285
- f.includes('Agent') ||
286
- f.includes('Orchestrat') ||
287
- f.includes('agent')
288
- )) {
289
- return true;
290
- }
291
- } catch (e) {
292
- continue;
293
- }
294
- }
295
-
296
- return false;
297
- } catch (error) {
298
- return false;
299
- }
300
- }
301
-
302
- /**
303
- * Detect API handlers
304
- */
305
- async detectAPIHandlers() {
306
- try {
307
- const handlerDirs = ['src/handlers', 'handlers', 'api'];
308
- for (const dir of handlerDirs) {
309
- try {
310
- const dirPath = path.join(this.workingDirectory, dir);
311
- await fs.access(dirPath);
312
- return true;
313
- } catch (e) {
314
- continue;
315
- }
316
- }
317
-
318
- return false;
319
- } catch (error) {
320
- return false;
321
- }
322
- }
323
-
324
- /**
325
- * Detect framework being used
326
- */
327
- async detectFramework(keyFiles) {
328
- if (!keyFiles.includes('package.json')) {
329
- return null;
330
- }
331
-
332
- try {
333
- const pkgPath = path.join(this.workingDirectory, 'package.json');
334
- const content = await fs.readFile(pkgPath, 'utf-8');
335
- const pkg = JSON.parse(content);
336
-
337
- const frameworks = {
338
- 'next': 'Next.js',
339
- 'nuxt': 'Nuxt.js',
340
- 'express': 'Express',
341
- 'fastify': 'Fastify',
342
- 'nestjs': 'NestJS',
343
- 'react': 'React',
344
- 'vue': 'Vue.js',
345
- 'angular': 'Angular'
346
- };
347
-
348
- for (const [key, name] of Object.entries(frameworks)) {
349
- if (pkg.dependencies?.[key] || pkg.devDependencies?.[key]) {
350
- return name;
351
- }
352
- }
353
-
354
- return null;
355
- } catch (error) {
356
- return null;
357
- }
358
- }
359
-
360
- /**
361
- * Determine deployment type from characteristics
362
- */
363
- determineDeploymentType(characteristics) {
364
- if (characteristics.hasSAM || characteristics.hasLambda) {
365
- return 'serverless';
366
- }
367
- if (characteristics.hasDocker) {
368
- return 'containerized';
369
- }
370
- if (characteristics.hasNodeJS || characteristics.hasPython) {
371
- return 'traditional';
372
- }
373
- return 'unknown';
374
- }
375
-
376
- /**
377
- * Map detected characteristics to standard categories
378
- */
379
- mapCharacteristicsToCategories(characteristics) {
380
- const categories = new Set();
381
-
382
- // Serverless/Lambda → serverless-saas-aws
383
- if (characteristics.hasLambda || characteristics.hasSAM) {
384
- categories.add('serverless-saas-aws');
385
- }
386
-
387
- // React/Frontend → frontend-development
388
- if (characteristics.hasReact) {
389
- categories.add('frontend-development');
390
- }
391
-
392
- // Database → database
393
- if (characteristics.hasDatabase) {
394
- categories.add('database');
395
- }
396
-
397
- // Multi-agent → multi-agent-orchestration
398
- if (characteristics.hasMultiAgent) {
399
- categories.add('multi-agent-orchestration');
400
- }
401
-
402
- // API handlers → backend
403
- if (characteristics.hasAPI) {
404
- categories.add('backend');
405
- }
406
-
407
- // Cost optimization always relevant for AWS
408
- if (characteristics.hasLambda || characteristics.hasSAM) {
409
- categories.add('cost-optimization');
410
- }
411
-
412
- // Testing if tests detected
413
- if (characteristics.hasTests) {
414
- categories.add('testing');
415
- }
416
-
417
- // Security/compliance always relevant
418
- categories.add('compliance-security');
419
-
420
- // Well-architected principles always relevant
421
- categories.add('well-architected');
422
-
423
- return Array.from(categories);
424
- }
425
-
426
- /**
427
- * Query relevant standards from database
428
- * Assumes Phase 1 schema (rapport.standards_patterns table exists)
429
- */
430
- async queryRelevantStandards({ categories, currentFile, characteristics }) {
431
- try {
432
- // Build file type filter
433
- let fileType = null;
434
- if (currentFile) {
435
- const ext = path.extname(currentFile);
436
- if (ext) {
437
- fileType = `*${ext}`;
438
- }
439
- }
440
-
441
- // Query standards matching categories
442
- const query = `
443
- SELECT
444
- pattern_id,
445
- element,
446
- rule,
447
- category,
448
- correlation,
449
- maturity,
450
- applicable_files,
451
- anti_patterns,
452
- examples,
453
- cost_impact,
454
- source
455
- FROM rapport.standards_patterns
456
- WHERE category = ANY($1::varchar[])
457
- AND maturity IN ('enforced', 'validated', 'recommended')
458
- ORDER BY
459
- CASE
460
- WHEN maturity = 'enforced' THEN 1
461
- WHEN maturity = 'validated' THEN 2
462
- ELSE 3
463
- END,
464
- correlation DESC
465
- `;
466
-
467
- const result = await executeQuery(query, [categories]);
468
- return result.rows;
469
- } catch (error) {
470
- // Database unavailable — fall back to reading YAML files directly
471
- console.warn('Standards patterns table not found. Falling back to file-based standards.');
472
- return this.loadStandardsFromFiles(categories, characteristics);
473
- }
474
- }
475
-
476
- /**
477
- * File-system fallback: load and filter standards from YAML files
478
- * Used when database is unavailable (local dev, first run, DB down)
479
- * @param {Array<string>} categories - Categories to filter by
480
- * @param {Object} characteristics - Project characteristics for relevance scoring
481
- * @returns {Promise<Array>} Ranked standards
482
- */
483
- async loadStandardsFromFiles(categories, characteristics = null) {
484
- try {
485
- const standardsPath = path.isAbsolute(this.standardsPath)
486
- ? this.standardsPath
487
- : path.join(this.workingDirectory, this.standardsPath);
488
-
489
- const ingestion = new StandardsIngestion({ standardsPath });
490
- const allPatterns = await ingestion.parseAllStandards();
491
-
492
- // Filter by requested categories and enforced/validated maturity
493
- const validMaturity = ['enforced', 'validated', 'recommended'];
494
- const categorySet = new Set(categories);
495
-
496
- const filtered = allPatterns.filter(p =>
497
- categorySet.has(p.category) && validMaturity.includes(p.maturity)
498
- );
499
-
500
- // Apply full relevance scoring if characteristics provided
501
- if (characteristics) {
502
- return this.rankStandards(filtered, characteristics, categories);
503
- }
504
-
505
- // Fallback: sort by maturity only (legacy behavior)
506
- return filtered.sort((a, b) => {
507
- const maturityOrder = { enforced: 1, validated: 2, recommended: 3 };
508
- return (maturityOrder[a.maturity] || 3) - (maturityOrder[b.maturity] || 3);
509
- });
510
- } catch (fallbackError) {
511
- console.error('File-based standards fallback failed:', fallbackError.message);
512
- return [];
513
- }
514
- }
515
-
516
- /**
517
- * Rank standards by relevance score
518
- */
519
- rankStandards(standards, characteristics, categories) {
520
- return standards.map(standard => {
521
- let score = 0;
522
-
523
- // Base score from correlation
524
- score += (standard.correlation || 1.0) * 40;
525
-
526
- // Maturity score
527
- const maturityScores = {
528
- 'enforced': 30,
529
- 'validated': 20,
530
- 'recommended': 10,
531
- 'provisional': 5
532
- };
533
- score += maturityScores[standard.maturity] || 0;
534
-
535
- // Category weight
536
- const categoryWeight = this.categoryWeights[standard.category] || 0.5;
537
- score += categoryWeight * 20;
538
-
539
- // File applicability bonus
540
- if (standard.applicable_files && standard.applicable_files.length > 0) {
541
- score += 5;
542
- }
543
-
544
- // Cost impact bonus (critical patterns)
545
- if (standard.cost_impact && standard.cost_impact.severity === 'critical') {
546
- score += 10;
547
- }
548
-
549
- // Anti-patterns bonus (important to know what NOT to do)
550
- if (standard.anti_patterns && Object.keys(standard.anti_patterns).length > 0) {
551
- score += 5;
552
- }
553
-
554
- // Workflow bonus (actionable procedures are high-value)
555
- if (standard.type === 'workflow' || (standard.tags && standard.tags.includes('workflow'))) {
556
- score += 10;
557
- }
558
-
559
- return {
560
- ...standard,
561
- relevance_score: Math.round(score * 10) / 10 // Round to 1 decimal
562
- };
563
- }).sort((a, b) => b.relevance_score - a.relevance_score);
564
- }
565
-
566
- /**
567
- * Format standards for injection into Claude Code context
568
- * Handles both standard rules and workflow procedures
569
- */
570
- formatForInjection(relevantStandards) {
571
- if (!relevantStandards || relevantStandards.length === 0) {
572
- return '';
573
- }
574
-
575
- const standards = [];
576
- const workflows = [];
577
-
578
- for (const item of relevantStandards) {
579
- if (item.type === 'workflow' || (item.tags && item.tags.includes('workflow') && item.examples && item.examples[0]?.type === 'workflow')) {
580
- workflows.push(item);
581
- } else {
582
- standards.push(item);
583
- }
584
- }
585
-
586
- let output = '';
587
-
588
- if (standards.length > 0) {
589
- output += '## Relevant Standards (Auto-Detected)\n\n';
590
-
591
- for (const standard of standards) {
592
- output += `### ${standard.element}\n`;
593
- output += `**Category**: ${standard.category}\n`;
594
- output += `**Maturity**: ${standard.maturity}\n`;
595
- output += `**Relevance**: ${standard.relevance_score}/100\n\n`;
596
- output += `${standard.rule}\n\n`;
597
-
598
- if (standard.examples && standard.examples.length > 0) {
599
- output += '**Examples**:\n';
600
- for (const example of standard.examples.slice(0, 2)) {
601
- output += `\`\`\`javascript\n${example.code || example}\n\`\`\`\n\n`;
602
- }
603
- }
604
-
605
- if (standard.anti_patterns && Object.keys(standard.anti_patterns).length > 0) {
606
- output += '**Anti-Patterns** (Avoid):\n';
607
- for (const [key, value] of Object.entries(standard.anti_patterns)) {
608
- output += `- ❌ ${key}: ${value}\n`;
609
- }
610
- output += '\n';
611
- }
612
-
613
- output += '---\n\n';
614
- }
615
- }
616
-
617
- if (workflows.length > 0) {
618
- output += '## Workflows (Auto-Detected)\n\n';
619
-
620
- for (const workflow of workflows) {
621
- const workflowData = workflow.examples && workflow.examples[0]?.type === 'workflow'
622
- ? workflow.examples[0]
623
- : null;
624
-
625
- output += `### ${workflow.element}\n`;
626
- output += `**Category**: ${workflow.category}\n`;
627
-
628
- if (workflowData) {
629
- output += `**When**: ${workflowData.trigger}\n\n`;
630
-
631
- if (workflowData.preconditions && workflowData.preconditions.length > 0) {
632
- output += '**Preconditions**:\n';
633
- for (const pre of workflowData.preconditions) {
634
- output += `- ${pre}\n`;
635
- }
636
- output += '\n';
637
- }
638
-
639
- if (workflowData.steps && workflowData.steps.length > 0) {
640
- output += '**Steps**:\n';
641
- for (const step of workflowData.steps) {
642
- const gateMarker = step.gate ? ' (GATE)' : '';
643
- output += `${step.index}. **${step.name}**${gateMarker} — ${step.description}\n`;
644
- if (step.command) {
645
- output += ` \`${step.command.trim().split('\n')[0]}\`\n`;
646
- }
647
- if (step.validation) {
648
- output += ` Verify: ${step.validation}\n`;
649
- }
650
- }
651
- output += '\n';
652
- }
653
- }
654
-
655
- if (workflow.anti_patterns && Object.keys(workflow.anti_patterns).length > 0) {
656
- output += '**Anti-Patterns** (Avoid):\n';
657
- for (const [key, value] of Object.entries(workflow.anti_patterns)) {
658
- output += `- ❌ ${key}: ${value}\n`;
659
- }
660
- output += '\n';
661
- }
662
-
663
- output += '---\n\n';
664
- }
665
- }
666
-
667
- return output;
668
- }
669
-
670
- /**
671
- * Get execution statistics
672
- */
673
- async getStatistics() {
674
- try {
675
- const query = `
676
- SELECT
677
- category,
678
- maturity,
679
- COUNT(*) as count
680
- FROM rapport.standards_patterns
681
- GROUP BY category, maturity
682
- ORDER BY category, maturity
683
- `;
684
-
685
- const result = await executeQuery(query);
686
- return result.rows;
687
- } catch (error) {
688
- console.error('Error getting statistics:', error);
689
- return [];
690
- }
691
- }
692
- }
693
-
694
- module.exports = { RelevanceDetector };