@equilateral_ai/mindmeld 3.5.3 → 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 (139) hide show
  1. package/hooks/session-start.js +312 -85
  2. package/package.json +20 -14
  3. package/scripts/init-project.js +9 -23
  4. package/src/client/dbShim.js +16 -0
  5. package/src/core/AuthManager.js +3 -2
  6. package/src/handlers/helpers/dbOperations.js +9 -46
  7. package/src/index.js +2 -217
  8. package/src/utils/piiMask.js +16 -0
  9. package/scripts/harvest.js +0 -601
  10. package/scripts/inject.js +0 -409
  11. package/scripts/mcp-bridge.js +0 -220
  12. package/scripts/repo-analyzer.js +0 -870
  13. package/scripts/standards.js +0 -285
  14. package/src/collaboration/CollaborationPrompt.js +0 -460
  15. package/src/core/AlertEngine.js +0 -813
  16. package/src/core/AlertNotifier.js +0 -363
  17. package/src/core/CorrelationAnalyzer.js +0 -931
  18. package/src/core/CrossReferenceEngine.js +0 -624
  19. package/src/core/CurationEngine.js +0 -688
  20. package/src/core/DeprecationScheduler.js +0 -183
  21. package/src/core/LoadBearingDetector.js +0 -242
  22. package/src/core/NotificationService.js +0 -1032
  23. package/src/core/RapportOrchestrator.js +0 -632
  24. package/src/core/RelevanceDetector.js +0 -694
  25. package/src/core/StandardLifecycle.js +0 -244
  26. package/src/core/StandardsIngestion.js +0 -991
  27. package/src/core/TeamLoadBearingDetector.js +0 -431
  28. package/src/core/parsers/adrParser.js +0 -479
  29. package/src/core/parsers/cursorRulesParser.js +0 -564
  30. package/src/core/parsers/eslintParser.js +0 -439
  31. package/src/database/dbOperations.js +0 -105
  32. package/src/handlers/activity/activityGetMe.js +0 -98
  33. package/src/handlers/activity/activityGetTeam.js +0 -175
  34. package/src/handlers/admin/adminSetup.js +0 -216
  35. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  36. package/src/handlers/alerts/alertsGet.js +0 -250
  37. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  38. package/src/handlers/analytics/coachingGet.js +0 -361
  39. package/src/handlers/analytics/convergenceGet.js +0 -236
  40. package/src/handlers/analytics/developerScoreGet.js +0 -137
  41. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  42. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  43. package/src/handlers/collaborators/collaboratorList.js +0 -82
  44. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  45. package/src/handlers/collaborators/inviteAccept.js +0 -122
  46. package/src/handlers/company/companyUsersDelete.js +0 -141
  47. package/src/handlers/company/companyUsersGet.js +0 -90
  48. package/src/handlers/company/companyUsersPost.js +0 -267
  49. package/src/handlers/company/companyUsersPut.js +0 -76
  50. package/src/handlers/context/contextGet.js +0 -57
  51. package/src/handlers/context/invariantsGet.js +0 -74
  52. package/src/handlers/context/loopsGet.js +0 -82
  53. package/src/handlers/context/notesCreate.js +0 -74
  54. package/src/handlers/context/purposeGet.js +0 -78
  55. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  56. package/src/handlers/correlations/correlationsGet.js +0 -93
  57. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  58. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  59. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  60. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  61. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  62. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  63. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  64. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  65. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  66. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  67. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  68. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  69. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  70. package/src/handlers/github/githubConnectionStatus.js +0 -49
  71. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  72. package/src/handlers/github/githubOAuthCallback.js +0 -178
  73. package/src/handlers/github/githubOAuthStart.js +0 -59
  74. package/src/handlers/github/githubPatternsReview.js +0 -76
  75. package/src/handlers/github/githubReposList.js +0 -105
  76. package/src/handlers/health/healthGet.js +0 -55
  77. package/src/handlers/helpers/auditLogger.js +0 -201
  78. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  79. package/src/handlers/helpers/decisionFrames.js +0 -29
  80. package/src/handlers/helpers/errorHandler.js +0 -49
  81. package/src/handlers/helpers/index.js +0 -138
  82. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  83. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  84. package/src/handlers/helpers/predictiveCache.js +0 -51
  85. package/src/handlers/helpers/projectAccess.js +0 -88
  86. package/src/handlers/helpers/responseUtil.js +0 -55
  87. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  88. package/src/handlers/mcp/mcpHandler.js +0 -569
  89. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  90. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  91. package/src/handlers/notifications/getPreferences.js +0 -84
  92. package/src/handlers/notifications/sendNotification.js +0 -170
  93. package/src/handlers/notifications/updatePreferences.js +0 -316
  94. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  95. package/src/handlers/patterns/patternUsagePost.js +0 -182
  96. package/src/handlers/patterns/patternViolationPost.js +0 -185
  97. package/src/handlers/projects/projectCreate.js +0 -248
  98. package/src/handlers/projects/projectDelete.js +0 -82
  99. package/src/handlers/projects/projectGet.js +0 -95
  100. package/src/handlers/projects/projectUpdate.js +0 -117
  101. package/src/handlers/reports/aiLeverage.js +0 -210
  102. package/src/handlers/reports/engineeringInvestment.js +0 -132
  103. package/src/handlers/reports/riskForecast.js +0 -206
  104. package/src/handlers/reports/standardsRoi.js +0 -254
  105. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  106. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  107. package/src/handlers/scheduled/generateAlerts.js +0 -135
  108. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  109. package/src/handlers/scheduled/refreshActivity.js +0 -21
  110. package/src/handlers/scheduled/scanCompliance.js +0 -334
  111. package/src/handlers/sessions/sessionEndPost.js +0 -180
  112. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  113. package/src/handlers/standards/catalogGet.js +0 -185
  114. package/src/handlers/standards/catalogSync.js +0 -120
  115. package/src/handlers/standards/discoveriesGet.js +0 -89
  116. package/src/handlers/standards/projectStandardsGet.js +0 -129
  117. package/src/handlers/standards/projectStandardsPut.js +0 -151
  118. package/src/handlers/standards/standardsAuditGet.js +0 -65
  119. package/src/handlers/standards/standardsParseUpload.js +0 -149
  120. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  121. package/src/handlers/standards/standardsTransition.js +0 -161
  122. package/src/handlers/stripe/addonManagePost.js +0 -240
  123. package/src/handlers/stripe/billingPortalPost.js +0 -93
  124. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  125. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  126. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  127. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  128. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  129. package/src/handlers/stripe/webhookPost.js +0 -482
  130. package/src/handlers/user/apiTokenCreate.js +0 -71
  131. package/src/handlers/user/apiTokenList.js +0 -64
  132. package/src/handlers/user/userSplashAck.js +0 -91
  133. package/src/handlers/user/userSplashGet.js +0 -211
  134. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  135. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  136. package/src/handlers/users/userEntitlementsGet.js +0 -89
  137. package/src/handlers/users/userGet.js +0 -118
  138. package/src/handlers/users/userProfilePut.js +0 -77
  139. 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
- });