@equilateral_ai/mindmeld 3.5.3 → 4.0.2

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 (138) hide show
  1. package/hooks/session-start.js +312 -85
  2. package/package.json +21 -13
  3. package/scripts/init-project.js +9 -23
  4. package/scripts/repo-analyzer.js +118 -2
  5. package/src/client/dbShim.js +16 -0
  6. package/src/core/AuthManager.js +3 -2
  7. package/src/handlers/helpers/dbOperations.js +9 -46
  8. package/src/index.js +2 -217
  9. package/src/utils/piiMask.js +16 -0
  10. package/scripts/inject.js +0 -409
  11. package/scripts/mcp-bridge.js +0 -220
  12. package/scripts/standards.js +0 -285
  13. package/src/collaboration/CollaborationPrompt.js +0 -460
  14. package/src/core/AlertEngine.js +0 -813
  15. package/src/core/AlertNotifier.js +0 -363
  16. package/src/core/CorrelationAnalyzer.js +0 -931
  17. package/src/core/CrossReferenceEngine.js +0 -624
  18. package/src/core/CurationEngine.js +0 -688
  19. package/src/core/DeprecationScheduler.js +0 -183
  20. package/src/core/LoadBearingDetector.js +0 -242
  21. package/src/core/NotificationService.js +0 -1032
  22. package/src/core/RapportOrchestrator.js +0 -632
  23. package/src/core/RelevanceDetector.js +0 -694
  24. package/src/core/StandardLifecycle.js +0 -244
  25. package/src/core/StandardsIngestion.js +0 -991
  26. package/src/core/TeamLoadBearingDetector.js +0 -431
  27. package/src/core/parsers/adrParser.js +0 -479
  28. package/src/core/parsers/cursorRulesParser.js +0 -564
  29. package/src/core/parsers/eslintParser.js +0 -439
  30. package/src/database/dbOperations.js +0 -105
  31. package/src/handlers/activity/activityGetMe.js +0 -98
  32. package/src/handlers/activity/activityGetTeam.js +0 -175
  33. package/src/handlers/admin/adminSetup.js +0 -216
  34. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  35. package/src/handlers/alerts/alertsGet.js +0 -250
  36. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  37. package/src/handlers/analytics/coachingGet.js +0 -361
  38. package/src/handlers/analytics/convergenceGet.js +0 -236
  39. package/src/handlers/analytics/developerScoreGet.js +0 -137
  40. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  41. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  42. package/src/handlers/collaborators/collaboratorList.js +0 -82
  43. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  44. package/src/handlers/collaborators/inviteAccept.js +0 -122
  45. package/src/handlers/company/companyUsersDelete.js +0 -141
  46. package/src/handlers/company/companyUsersGet.js +0 -90
  47. package/src/handlers/company/companyUsersPost.js +0 -267
  48. package/src/handlers/company/companyUsersPut.js +0 -76
  49. package/src/handlers/context/contextGet.js +0 -57
  50. package/src/handlers/context/invariantsGet.js +0 -74
  51. package/src/handlers/context/loopsGet.js +0 -82
  52. package/src/handlers/context/notesCreate.js +0 -74
  53. package/src/handlers/context/purposeGet.js +0 -78
  54. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  55. package/src/handlers/correlations/correlationsGet.js +0 -93
  56. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  57. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  58. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  59. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  60. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  61. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  62. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  63. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  64. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  65. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  66. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  67. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  68. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  69. package/src/handlers/github/githubConnectionStatus.js +0 -49
  70. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  71. package/src/handlers/github/githubOAuthCallback.js +0 -178
  72. package/src/handlers/github/githubOAuthStart.js +0 -59
  73. package/src/handlers/github/githubPatternsReview.js +0 -76
  74. package/src/handlers/github/githubReposList.js +0 -105
  75. package/src/handlers/health/healthGet.js +0 -55
  76. package/src/handlers/helpers/auditLogger.js +0 -201
  77. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  78. package/src/handlers/helpers/decisionFrames.js +0 -29
  79. package/src/handlers/helpers/errorHandler.js +0 -49
  80. package/src/handlers/helpers/index.js +0 -138
  81. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  82. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  83. package/src/handlers/helpers/predictiveCache.js +0 -51
  84. package/src/handlers/helpers/projectAccess.js +0 -88
  85. package/src/handlers/helpers/responseUtil.js +0 -55
  86. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  87. package/src/handlers/mcp/mcpHandler.js +0 -569
  88. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  89. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  90. package/src/handlers/notifications/getPreferences.js +0 -84
  91. package/src/handlers/notifications/sendNotification.js +0 -170
  92. package/src/handlers/notifications/updatePreferences.js +0 -316
  93. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  94. package/src/handlers/patterns/patternUsagePost.js +0 -182
  95. package/src/handlers/patterns/patternViolationPost.js +0 -185
  96. package/src/handlers/projects/projectCreate.js +0 -248
  97. package/src/handlers/projects/projectDelete.js +0 -82
  98. package/src/handlers/projects/projectGet.js +0 -95
  99. package/src/handlers/projects/projectUpdate.js +0 -117
  100. package/src/handlers/reports/aiLeverage.js +0 -210
  101. package/src/handlers/reports/engineeringInvestment.js +0 -132
  102. package/src/handlers/reports/riskForecast.js +0 -206
  103. package/src/handlers/reports/standardsRoi.js +0 -254
  104. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  105. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  106. package/src/handlers/scheduled/generateAlerts.js +0 -135
  107. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  108. package/src/handlers/scheduled/refreshActivity.js +0 -21
  109. package/src/handlers/scheduled/scanCompliance.js +0 -334
  110. package/src/handlers/sessions/sessionEndPost.js +0 -180
  111. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  112. package/src/handlers/standards/catalogGet.js +0 -185
  113. package/src/handlers/standards/catalogSync.js +0 -120
  114. package/src/handlers/standards/discoveriesGet.js +0 -89
  115. package/src/handlers/standards/projectStandardsGet.js +0 -129
  116. package/src/handlers/standards/projectStandardsPut.js +0 -151
  117. package/src/handlers/standards/standardsAuditGet.js +0 -65
  118. package/src/handlers/standards/standardsParseUpload.js +0 -149
  119. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  120. package/src/handlers/standards/standardsTransition.js +0 -161
  121. package/src/handlers/stripe/addonManagePost.js +0 -240
  122. package/src/handlers/stripe/billingPortalPost.js +0 -93
  123. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  124. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  125. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  126. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  127. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  128. package/src/handlers/stripe/webhookPost.js +0 -482
  129. package/src/handlers/user/apiTokenCreate.js +0 -71
  130. package/src/handlers/user/apiTokenList.js +0 -64
  131. package/src/handlers/user/userSplashAck.js +0 -91
  132. package/src/handlers/user/userSplashGet.js +0 -211
  133. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  134. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  135. package/src/handlers/users/userEntitlementsGet.js +0 -89
  136. package/src/handlers/users/userGet.js +0 -118
  137. package/src/handlers/users/userProfilePut.js +0 -77
  138. package/src/handlers/webhooks/githubWebhook.js +0 -215
@@ -1,439 +0,0 @@
1
- /**
2
- * ESLint Config Parser - Parse ESLint configurations into YAML standards format
3
- *
4
- * Accepts ESLint config content (JSON or JS module format) and maps rules to
5
- * YAML-compatible standards objects matching the equilateral-standards schema.
6
- *
7
- * Rule severity mapping:
8
- * "error" / 2 -> ALWAYS (for positive rules) or NEVER (for "no-" rules)
9
- * "warn" / 1 -> PREFER (for positive rules) or AVOID (for "no-" rules)
10
- * "off" / 0 -> skipped
11
- *
12
- * @module parsers/eslintParser
13
- */
14
-
15
- /**
16
- * Well-known ESLint rule descriptions for common rules
17
- * Maps rule name to a human-readable description
18
- */
19
- const RULE_DESCRIPTIONS = {
20
- // Possible errors
21
- 'no-console': 'Console statements in production',
22
- 'no-debugger': 'Debugger statements in production code',
23
- 'no-dupe-args': 'Duplicate arguments in function definitions',
24
- 'no-dupe-keys': 'Duplicate keys in object literals',
25
- 'no-duplicate-case': 'Duplicate case labels in switch statements',
26
- 'no-empty': 'Empty block statements',
27
- 'no-extra-semi': 'Unnecessary semicolons',
28
- 'no-unreachable': 'Unreachable code after return, throw, continue, or break',
29
- 'no-unsafe-negation': 'Negating the left operand of relational operators',
30
-
31
- // Best practices
32
- 'no-eval': 'Use of eval()',
33
- 'no-implied-eval': 'Use of implied eval() through setTimeout/setInterval strings',
34
- 'no-unused-vars': 'Leave unused variables',
35
- 'no-unused-expressions': 'Unused expressions that have no effect',
36
- 'no-var': 'Use of var declarations',
37
- 'no-shadow': 'Variable declarations that shadow outer scope variables',
38
- 'no-param-reassign': 'Reassignment of function parameters',
39
- 'no-return-await': 'Unnecessary return await',
40
- 'no-throw-literal': 'Throwing literals as exceptions',
41
- 'no-useless-catch': 'Catch clauses that only rethrow',
42
- 'no-useless-return': 'Redundant return statements',
43
-
44
- // Style & conventions
45
- 'eqeqeq': 'Use strict equality operators (=== and !==)',
46
- 'curly': 'Use curly braces for all control statements',
47
- 'prefer-const': 'Use const for variables that are never reassigned',
48
- 'prefer-template': 'Use template literals instead of string concatenation',
49
- 'prefer-arrow-callback': 'Use arrow functions for callbacks',
50
- 'prefer-destructuring': 'Use destructuring from arrays and objects',
51
- 'prefer-rest-params': 'Use rest parameters instead of arguments object',
52
- 'prefer-spread': 'Use spread syntax instead of .apply()',
53
- 'arrow-body-style': 'Require braces around arrow function bodies',
54
- 'consistent-return': 'Require consistent return statements',
55
- 'default-case': 'Require default case in switch statements',
56
- 'dot-notation': 'Use dot notation whenever possible',
57
- 'no-else-return': 'Disallow else blocks after return in if statements',
58
-
59
- // ES6+
60
- 'no-duplicate-imports': 'Duplicate imports from the same module',
61
- 'no-useless-constructor': 'Unnecessary constructors',
62
- 'no-useless-rename': 'Renaming imports/exports/destructured to the same name',
63
-
64
- // Node.js
65
- 'no-process-exit': 'Use of process.exit()',
66
- 'no-path-concat': 'String concatenation with __dirname and __filename',
67
- 'callback-return': 'Require return after callback',
68
- 'handle-callback-err': 'Handle callback error parameters',
69
-
70
- // TypeScript (common plugin rules)
71
- '@typescript-eslint/no-explicit-any': 'Use of explicit any type',
72
- '@typescript-eslint/no-unused-vars': 'Leave unused variables',
73
- '@typescript-eslint/explicit-function-return-type': 'Require explicit return types on functions',
74
- '@typescript-eslint/no-non-null-assertion': 'Use of non-null assertion operator (!)',
75
-
76
- // React (common plugin rules)
77
- 'react/no-direct-mutation-state': 'Direct mutation of state',
78
- 'react/no-unused-state': 'Unused state fields',
79
- 'react/jsx-no-bind': 'Use of .bind() or arrow functions in JSX props',
80
- 'react/jsx-key': 'Missing key prop in iterators/collection literals',
81
- 'react-hooks/rules-of-hooks': 'Follow the Rules of Hooks',
82
- 'react-hooks/exhaustive-deps': 'Verify the list of dependencies for Hooks'
83
- };
84
-
85
- /**
86
- * Parse ESLint config content into YAML-compatible standards object
87
- *
88
- * @param {string} content - ESLint config content (JSON string or JS module string)
89
- * @param {Object} options - Parser options
90
- * @param {string} options.filename - Source filename
91
- * @param {string} options.category - Standards category override
92
- * @returns {Object} YAML-compatible standards object
93
- */
94
- function parseEslint(content, options = {}) {
95
- if (!content || typeof content !== 'string') {
96
- throw new Error('ESLint config content is required and must be a string');
97
- }
98
-
99
- const filename = options.filename || '.eslintrc';
100
- const config = parseConfigContent(content);
101
-
102
- if (!config || typeof config !== 'object') {
103
- throw new Error('Failed to parse ESLint configuration');
104
- }
105
-
106
- const rules = extractRules(config);
107
- const plugins = extractPlugins(config);
108
- const extendsConfigs = extractExtends(config);
109
- const category = options.category || inferCategory(plugins, extendsConfigs);
110
-
111
- const id = generateId(filename);
112
-
113
- return {
114
- id,
115
- category,
116
- priority: determinePriority(rules),
117
- rules,
118
- anti_patterns: extractAntiPatterns(rules),
119
- context: {
120
- source_format: 'eslint',
121
- source_file: filename,
122
- extends: extendsConfigs,
123
- plugins
124
- },
125
- tags: buildTags(plugins, extendsConfigs),
126
- updated: new Date().toISOString().split('T')[0]
127
- };
128
- }
129
-
130
- /**
131
- * Parse config content from JSON or JS module format
132
- *
133
- * @param {string} content - Raw config content
134
- * @returns {Object} Parsed config object
135
- */
136
- function parseConfigContent(content) {
137
- const trimmed = content.trim();
138
-
139
- // Try JSON first
140
- try {
141
- return JSON.parse(trimmed);
142
- } catch (_jsonError) {
143
- // Not valid JSON, try extracting object from JS module
144
- }
145
-
146
- // Try extracting from module.exports = { ... }
147
- const moduleExportsMatch = trimmed.match(/module\.exports\s*=\s*(\{[\s\S]*\})\s*;?\s*$/);
148
- if (moduleExportsMatch) {
149
- try {
150
- // Use Function constructor to safely evaluate the object literal
151
- // This handles JS features like trailing commas and comments
152
- const fn = new Function(`return (${moduleExportsMatch[1]})`);
153
- return fn();
154
- } catch (_evalError) {
155
- // Fall through to next attempt
156
- }
157
- }
158
-
159
- // Try extracting from export default { ... } (flat config)
160
- const exportDefaultMatch = trimmed.match(/export\s+default\s+(\{[\s\S]*\})\s*;?\s*$/);
161
- if (exportDefaultMatch) {
162
- try {
163
- const fn = new Function(`return (${exportDefaultMatch[1]})`);
164
- return fn();
165
- } catch (_evalError) {
166
- // Fall through
167
- }
168
- }
169
-
170
- // Try extracting from flat config array format: export default [...]
171
- const flatArrayMatch = trimmed.match(/(?:module\.exports|export\s+default)\s*=?\s*(\[[\s\S]*\])\s*;?\s*$/);
172
- if (flatArrayMatch) {
173
- try {
174
- const fn = new Function(`return (${flatArrayMatch[1]})`);
175
- const arr = fn();
176
- // Merge all config objects in the array
177
- if (Array.isArray(arr)) {
178
- return arr.reduce((merged, item) => {
179
- if (item && typeof item === 'object') {
180
- if (item.rules) merged.rules = { ...merged.rules, ...item.rules };
181
- if (item.plugins) merged.plugins = [...(merged.plugins || []), ...(Array.isArray(item.plugins) ? item.plugins : [])];
182
- }
183
- return merged;
184
- }, { rules: {}, plugins: [] });
185
- }
186
- } catch (_evalError) {
187
- // Fall through
188
- }
189
- }
190
-
191
- throw new Error('Unable to parse ESLint config: unsupported format');
192
- }
193
-
194
- /**
195
- * Extract and map ESLint rules to YAML standards rules
196
- *
197
- * @param {Object} config - Parsed ESLint config
198
- * @returns {Array<Object>} Array of rule objects with action and rule text
199
- */
200
- function extractRules(config) {
201
- const configRules = config.rules || {};
202
- const yamlRules = [];
203
-
204
- for (const [ruleName, ruleValue] of Object.entries(configRules)) {
205
- const severity = normalizeSeverity(ruleValue);
206
-
207
- // Skip disabled rules
208
- if (severity === 0) continue;
209
-
210
- const isNegativeRule = ruleName.startsWith('no-') ||
211
- ruleName.includes('/no-') ||
212
- ruleName.includes('no-direct') ||
213
- ruleName.includes('no-unused');
214
-
215
- const action = mapSeverityToAction(severity, isNegativeRule);
216
- const description = getDescription(ruleName);
217
- const ruleOptions = extractRuleOptions(ruleValue);
218
-
219
- const rule = {
220
- action,
221
- rule: description
222
- };
223
-
224
- // Include rule options as applies_to context if meaningful
225
- if (ruleOptions) {
226
- rule.options = ruleOptions;
227
- }
228
-
229
- yamlRules.push(rule);
230
- }
231
-
232
- return yamlRules;
233
- }
234
-
235
- /**
236
- * Normalize ESLint rule severity to numeric value
237
- *
238
- * @param {*} ruleValue - ESLint rule value (string, number, or array)
239
- * @returns {number} 0 (off), 1 (warn), or 2 (error)
240
- */
241
- function normalizeSeverity(ruleValue) {
242
- const value = Array.isArray(ruleValue) ? ruleValue[0] : ruleValue;
243
-
244
- if (typeof value === 'number') return value;
245
- if (value === 'error') return 2;
246
- if (value === 'warn') return 1;
247
- if (value === 'off') return 0;
248
-
249
- return 0;
250
- }
251
-
252
- /**
253
- * Map ESLint severity to YAML action type
254
- *
255
- * @param {number} severity - Numeric severity (1 or 2)
256
- * @param {boolean} isNegative - Whether the rule is a "no-" rule
257
- * @returns {string} Action type
258
- */
259
- function mapSeverityToAction(severity, isNegative) {
260
- if (severity === 2) {
261
- return isNegative ? 'NEVER' : 'ALWAYS';
262
- }
263
- // severity === 1
264
- return isNegative ? 'AVOID' : 'PREFER';
265
- }
266
-
267
- /**
268
- * Get a human-readable description for an ESLint rule
269
- *
270
- * @param {string} ruleName - ESLint rule name
271
- * @returns {string} Human-readable description
272
- */
273
- function getDescription(ruleName) {
274
- // Check known descriptions
275
- if (RULE_DESCRIPTIONS[ruleName]) {
276
- return RULE_DESCRIPTIONS[ruleName];
277
- }
278
-
279
- // Generate description from rule name
280
- const parts = ruleName.split('/');
281
- const name = parts[parts.length - 1];
282
-
283
- return name
284
- .replace(/^no-/, 'Disallow ')
285
- .replace(/^prefer-/, 'Prefer ')
286
- .replace(/^require-/, 'Require ')
287
- .replace(/-/g, ' ')
288
- .replace(/^\w/, c => c.toUpperCase());
289
- }
290
-
291
- /**
292
- * Extract rule options from array-format rule values
293
- *
294
- * @param {*} ruleValue - ESLint rule value
295
- * @returns {*} Rule options or null
296
- */
297
- function extractRuleOptions(ruleValue) {
298
- if (!Array.isArray(ruleValue) || ruleValue.length <= 1) return null;
299
- const options = ruleValue.slice(1);
300
- return options.length === 1 ? options[0] : options;
301
- }
302
-
303
- /**
304
- * Extract anti-patterns from NEVER/AVOID rules
305
- *
306
- * @param {Array<Object>} rules - Parsed rules
307
- * @returns {Array<string>} Anti-pattern descriptions
308
- */
309
- function extractAntiPatterns(rules) {
310
- return rules
311
- .filter(r => r.action === 'NEVER' || r.action === 'AVOID')
312
- .map(r => r.rule);
313
- }
314
-
315
- /**
316
- * Extract plugin names from config
317
- *
318
- * @param {Object} config - Parsed ESLint config
319
- * @returns {Array<string>} Plugin names
320
- */
321
- function extractPlugins(config) {
322
- if (!config.plugins) return [];
323
-
324
- if (Array.isArray(config.plugins)) {
325
- return config.plugins.map(p => typeof p === 'string' ? p : '').filter(Boolean);
326
- }
327
-
328
- // Object format (flat config)
329
- if (typeof config.plugins === 'object') {
330
- return Object.keys(config.plugins);
331
- }
332
-
333
- return [];
334
- }
335
-
336
- /**
337
- * Extract extends configurations
338
- *
339
- * @param {Object} config - Parsed ESLint config
340
- * @returns {Array<string>} Extends config names
341
- */
342
- function extractExtends(config) {
343
- if (!config.extends) return [];
344
- if (typeof config.extends === 'string') return [config.extends];
345
- if (Array.isArray(config.extends)) return config.extends;
346
- return [];
347
- }
348
-
349
- /**
350
- * Infer standards category from plugins and extends
351
- *
352
- * @param {Array<string>} plugins - Plugin names
353
- * @param {Array<string>} extendsConfigs - Extended config names
354
- * @returns {string} Inferred category
355
- */
356
- function inferCategory(plugins, extendsConfigs) {
357
- const all = [...plugins, ...extendsConfigs].map(s => s.toLowerCase());
358
-
359
- if (all.some(s => s.includes('react') || s.includes('jsx'))) return 'frontend-development';
360
- if (all.some(s => s.includes('typescript'))) return 'frontend-development';
361
- if (all.some(s => s.includes('vue'))) return 'frontend-development';
362
- if (all.some(s => s.includes('node'))) return 'backend';
363
- if (all.some(s => s.includes('security'))) return 'compliance-security';
364
-
365
- return 'general';
366
- }
367
-
368
- /**
369
- * Generate standards ID from filename
370
- *
371
- * @param {string} filename - Source filename
372
- * @returns {string} Generated ID
373
- */
374
- function generateId(filename) {
375
- const slug = filename
376
- .replace(/\.(json|js|cjs|mjs|yaml|yml)$/i, '')
377
- .replace(/[^a-z0-9]+/gi, '-')
378
- .toLowerCase();
379
-
380
- return `eslint-${slug}`;
381
- }
382
-
383
- /**
384
- * Determine priority based on rule severity distribution
385
- *
386
- * @param {Array<Object>} rules - Extracted rules
387
- * @returns {number} Priority (10, 20, or 30)
388
- */
389
- function determinePriority(rules) {
390
- const enforcedCount = rules.filter(r =>
391
- r.action === 'ALWAYS' || r.action === 'NEVER'
392
- ).length;
393
-
394
- const total = rules.length;
395
- if (total === 0) return 30;
396
-
397
- // Majority enforced -> high priority
398
- if (enforcedCount / total > 0.5) return 10;
399
- if (enforcedCount > 0) return 20;
400
-
401
- return 30;
402
- }
403
-
404
- /**
405
- * Build tags from plugins and extends
406
- *
407
- * @param {Array<string>} plugins - Plugin names
408
- * @param {Array<string>} extendsConfigs - Extended config names
409
- * @returns {Array<string>} Tags
410
- */
411
- function buildTags(plugins, extendsConfigs) {
412
- const tags = ['eslint', 'linting'];
413
-
414
- for (const plugin of plugins) {
415
- const cleaned = plugin
416
- .replace(/^eslint-plugin-/, '')
417
- .replace(/^@[^/]+\//, '')
418
- .toLowerCase();
419
- tags.push(cleaned);
420
- }
421
-
422
- for (const ext of extendsConfigs) {
423
- if (ext.includes('recommended')) tags.push('recommended');
424
- if (ext.includes('strict')) tags.push('strict');
425
- if (ext.includes('airbnb')) tags.push('airbnb');
426
- if (ext.includes('prettier')) tags.push('prettier');
427
- if (ext.includes('standard')) tags.push('standard');
428
- }
429
-
430
- return [...new Set(tags)];
431
- }
432
-
433
- module.exports = {
434
- parseEslint,
435
- extractRules,
436
- normalizeSeverity,
437
- mapSeverityToAction,
438
- getDescription
439
- };
@@ -1,105 +0,0 @@
1
- /**
2
- * Rapport v3 - Database Operations
3
- *
4
- * Provides database query execution following Tim-Combo backend_handler_standards.md
5
- * Uses cached single client (NOT connection pools) per Lambda database standards
6
- */
7
-
8
- const { Client } = require('pg');
9
-
10
- // Cached client for connection reuse across warm Lambda invocations
11
- let cachedClient = null;
12
-
13
- /**
14
- * Get or create database client
15
- *
16
- * Follows Lambda database standards:
17
- * - NEVER use connection pools (Lambda handles one request at a time)
18
- * - Cache single client for reuse across warm invocations
19
- * - Use environment variables (NOT runtime SSM fetches)
20
- *
21
- * @returns {Promise<Client>} PostgreSQL client
22
- */
23
- async function getClient() {
24
- if (cachedClient && cachedClient._connected) {
25
- return cachedClient;
26
- }
27
-
28
- const client = new Client({
29
- host: process.env.DB_HOST,
30
- port: process.env.DB_PORT || 5432,
31
- database: process.env.DB_NAME,
32
- user: process.env.DB_USER,
33
- password: process.env.DB_PASSWORD,
34
- ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false
35
- });
36
-
37
- await client.connect();
38
- client._connected = true;
39
-
40
- cachedClient = client;
41
- return client;
42
- }
43
-
44
- /**
45
- * Execute a database query
46
- *
47
- * Standard pattern from backend_handler_standards.md
48
- *
49
- * @param {string} query - SQL query
50
- * @param {Array} params - Query parameters
51
- * @returns {Promise<Object>} Query result
52
- */
53
- async function executeQuery(query, params = []) {
54
- const client = await getClient();
55
-
56
- try {
57
- const result = await client.query(query, params);
58
- return result;
59
- } catch (error) {
60
- console.error('[dbOperations] Query error:', {
61
- error: error.message,
62
- query: query.substring(0, 200),
63
- params: params
64
- });
65
- throw error;
66
- }
67
- }
68
-
69
- /**
70
- * Execute multiple queries in a transaction
71
- *
72
- * @param {Function} callback - Async function that receives client
73
- * @returns {Promise<any>} Callback result
74
- */
75
- async function executeTransaction(callback) {
76
- const client = await getClient();
77
-
78
- try {
79
- await client.query('BEGIN');
80
- const result = await callback(client);
81
- await client.query('COMMIT');
82
- return result;
83
- } catch (error) {
84
- await client.query('ROLLBACK');
85
- console.error('[dbOperations] Transaction error:', error);
86
- throw error;
87
- }
88
- }
89
-
90
- /**
91
- * Close database connection (for graceful shutdown)
92
- */
93
- async function closeConnection() {
94
- if (cachedClient) {
95
- await cachedClient.end();
96
- cachedClient = null;
97
- }
98
- }
99
-
100
- module.exports = {
101
- executeQuery,
102
- executeTransaction,
103
- closeConnection,
104
- getClient
105
- };
@@ -1,98 +0,0 @@
1
- /**
2
- * Activity Get Me Handler
3
- * Retrieves current user's activity summary
4
- *
5
- * GET /api/activity/me
6
- * Auth: Cognito JWT required
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
10
-
11
- exports.handler = wrapHandler(async ({ requestContext }) => {
12
- const Request_ID = requestContext.requestId;
13
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
14
-
15
- if (!email) {
16
- return createErrorResponse(401, 'Authentication required');
17
- }
18
-
19
- // Get activity from materialized view
20
- const result = await executeQuery(`
21
- SELECT
22
- email_address,
23
- display_name,
24
- sessions_30d,
25
- sessions_7d,
26
- last_session,
27
- avg_session_duration_seconds,
28
- commits_30d,
29
- commits_7d,
30
- last_commit,
31
- days_since_commit,
32
- prs_opened_30d,
33
- prs_merged_30d,
34
- avg_pr_review_hours,
35
- commits_within_24h_of_session,
36
- session_to_commit_conversion_pct
37
- FROM rapport.mv_developer_activity
38
- WHERE email_address = $1
39
- `, [email]);
40
-
41
- if (result.rowCount === 0) {
42
- // Return empty activity for new users
43
- return createSuccessResponse(
44
- {
45
- Records: [{
46
- email_address: email,
47
- sessions_30d: 0,
48
- sessions_7d: 0,
49
- commits_30d: 0,
50
- commits_7d: 0,
51
- prs_opened_30d: 0,
52
- prs_merged_30d: 0,
53
- session_to_commit_conversion_pct: 0
54
- }]
55
- },
56
- 'Activity retrieved (new user)',
57
- { Total_Records: 1, Request_ID, Timestamp: new Date().toISOString() }
58
- );
59
- }
60
-
61
- const activity = result.rows[0];
62
-
63
- return createSuccessResponse(
64
- {
65
- Records: [{
66
- email_address: activity.email_address,
67
- display_name: activity.display_name,
68
- sessions: {
69
- last_30_days: parseInt(activity.sessions_30d) || 0,
70
- last_7_days: parseInt(activity.sessions_7d) || 0,
71
- last_session: activity.last_session,
72
- avg_duration_minutes: activity.avg_session_duration_seconds
73
- ? Math.round(activity.avg_session_duration_seconds / 60)
74
- : null
75
- },
76
- commits: {
77
- last_30_days: parseInt(activity.commits_30d) || 0,
78
- last_7_days: parseInt(activity.commits_7d) || 0,
79
- last_commit: activity.last_commit,
80
- days_since_commit: activity.days_since_commit !== null ? parseInt(activity.days_since_commit) : null
81
- },
82
- pull_requests: {
83
- opened_30d: parseInt(activity.prs_opened_30d) || 0,
84
- merged_30d: parseInt(activity.prs_merged_30d) || 0,
85
- avg_review_hours: activity.avg_pr_review_hours
86
- ? parseFloat(activity.avg_pr_review_hours).toFixed(1)
87
- : null
88
- },
89
- value_correlation: {
90
- commits_within_24h_of_session: parseInt(activity.commits_within_24h_of_session) || 0,
91
- session_to_commit_conversion_pct: parseFloat(activity.session_to_commit_conversion_pct) || 0
92
- }
93
- }]
94
- },
95
- 'Activity retrieved',
96
- { Total_Records: 1, Request_ID, Timestamp: new Date().toISOString() }
97
- );
98
- });