@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.
- package/hooks/session-end.js +25 -0
- package/hooks/session-start.js +363 -83
- package/hooks/session-watcher.js +585 -0
- package/package.json +19 -13
- package/scripts/init-project.js +9 -23
- package/src/client/dbShim.js +16 -0
- package/src/core/AuthManager.js +3 -2
- package/src/handlers/helpers/dbOperations.js +9 -46
- package/src/index.js +2 -217
- package/src/utils/piiMask.js +16 -0
- package/scripts/harvest.js +0 -601
- package/scripts/inject.js +0 -409
- package/scripts/mcp-bridge.js +0 -220
- package/scripts/repo-analyzer.js +0 -870
- package/src/collaboration/CollaborationPrompt.js +0 -460
- package/src/core/AlertEngine.js +0 -813
- package/src/core/AlertNotifier.js +0 -363
- package/src/core/CorrelationAnalyzer.js +0 -931
- package/src/core/CrossReferenceEngine.js +0 -624
- package/src/core/CurationEngine.js +0 -688
- package/src/core/DeprecationScheduler.js +0 -183
- package/src/core/LoadBearingDetector.js +0 -242
- package/src/core/NotificationService.js +0 -1032
- package/src/core/RapportOrchestrator.js +0 -632
- package/src/core/RelevanceDetector.js +0 -694
- package/src/core/StandardLifecycle.js +0 -244
- package/src/core/StandardsIngestion.js +0 -991
- package/src/core/TeamLoadBearingDetector.js +0 -431
- package/src/core/parsers/adrParser.js +0 -479
- package/src/core/parsers/cursorRulesParser.js +0 -564
- package/src/core/parsers/eslintParser.js +0 -439
- package/src/database/dbOperations.js +0 -105
- package/src/handlers/activity/activityGetMe.js +0 -98
- package/src/handlers/activity/activityGetTeam.js +0 -175
- package/src/handlers/admin/adminSetup.js +0 -216
- package/src/handlers/alerts/alertsAcknowledge.js +0 -92
- package/src/handlers/alerts/alertsGet.js +0 -250
- package/src/handlers/analytics/activitySummaryGet.js +0 -234
- package/src/handlers/analytics/coachingGet.js +0 -361
- package/src/handlers/analytics/convergenceGet.js +0 -236
- package/src/handlers/analytics/developerScoreGet.js +0 -137
- package/src/handlers/collaborators/collaboratorAdd.js +0 -200
- package/src/handlers/collaborators/collaboratorInvite.js +0 -219
- package/src/handlers/collaborators/collaboratorList.js +0 -82
- package/src/handlers/collaborators/collaboratorRemove.js +0 -128
- package/src/handlers/collaborators/inviteAccept.js +0 -122
- package/src/handlers/company/companyUsersDelete.js +0 -141
- package/src/handlers/company/companyUsersGet.js +0 -90
- package/src/handlers/company/companyUsersPost.js +0 -267
- package/src/handlers/company/companyUsersPut.js +0 -76
- package/src/handlers/context/contextGet.js +0 -57
- package/src/handlers/context/invariantsGet.js +0 -74
- package/src/handlers/context/loopsGet.js +0 -82
- package/src/handlers/context/notesCreate.js +0 -74
- package/src/handlers/context/purposeGet.js +0 -78
- package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
- package/src/handlers/correlations/correlationsGet.js +0 -93
- package/src/handlers/correlations/correlationsProjectGet.js +0 -153
- package/src/handlers/enterprise/controlTowerGet.js +0 -224
- package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
- package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
- package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
- package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
- package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
- package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
- package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
- package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
- package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
- package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
- package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
- package/src/handlers/github/githubConnectionStatus.js +0 -49
- package/src/handlers/github/githubDiscoverPatterns.js +0 -621
- package/src/handlers/github/githubOAuthCallback.js +0 -178
- package/src/handlers/github/githubOAuthStart.js +0 -59
- package/src/handlers/github/githubPatternsReview.js +0 -76
- package/src/handlers/github/githubReposList.js +0 -105
- package/src/handlers/health/healthGet.js +0 -55
- package/src/handlers/helpers/auditLogger.js +0 -201
- package/src/handlers/helpers/checkSuperAdmin.js +0 -84
- package/src/handlers/helpers/decisionFrames.js +0 -29
- package/src/handlers/helpers/errorHandler.js +0 -49
- package/src/handlers/helpers/index.js +0 -138
- package/src/handlers/helpers/lambdaWrapper.js +0 -60
- package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
- package/src/handlers/helpers/predictiveCache.js +0 -51
- package/src/handlers/helpers/projectAccess.js +0 -88
- package/src/handlers/helpers/responseUtil.js +0 -55
- package/src/handlers/helpers/subscriptionTiers.js +0 -1168
- package/src/handlers/mcp/mcpHandler.js +0 -569
- package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
- package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
- package/src/handlers/notifications/getPreferences.js +0 -84
- package/src/handlers/notifications/sendNotification.js +0 -170
- package/src/handlers/notifications/updatePreferences.js +0 -316
- package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
- package/src/handlers/patterns/patternUsagePost.js +0 -182
- package/src/handlers/patterns/patternViolationPost.js +0 -185
- package/src/handlers/projects/projectCreate.js +0 -248
- package/src/handlers/projects/projectDelete.js +0 -82
- package/src/handlers/projects/projectGet.js +0 -95
- package/src/handlers/projects/projectUpdate.js +0 -117
- package/src/handlers/reports/aiLeverage.js +0 -210
- package/src/handlers/reports/engineeringInvestment.js +0 -132
- package/src/handlers/reports/riskForecast.js +0 -206
- package/src/handlers/reports/standardsRoi.js +0 -254
- package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
- package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
- package/src/handlers/scheduled/generateAlerts.js +0 -135
- package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
- package/src/handlers/scheduled/refreshActivity.js +0 -21
- package/src/handlers/scheduled/scanCompliance.js +0 -334
- package/src/handlers/sessions/sessionEndPost.js +0 -180
- package/src/handlers/sessions/sessionStandardsPost.js +0 -171
- package/src/handlers/standards/catalogGet.js +0 -185
- package/src/handlers/standards/catalogSync.js +0 -120
- package/src/handlers/standards/discoveriesGet.js +0 -89
- package/src/handlers/standards/projectStandardsGet.js +0 -129
- package/src/handlers/standards/projectStandardsPut.js +0 -151
- package/src/handlers/standards/standardsAuditGet.js +0 -65
- package/src/handlers/standards/standardsParseUpload.js +0 -149
- package/src/handlers/standards/standardsRelevantPost.js +0 -405
- package/src/handlers/standards/standardsTransition.js +0 -161
- package/src/handlers/stripe/addonManagePost.js +0 -240
- package/src/handlers/stripe/billingPortalPost.js +0 -93
- package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
- package/src/handlers/stripe/seatsUpdatePost.js +0 -185
- package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
- package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
- package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
- package/src/handlers/stripe/webhookPost.js +0 -482
- package/src/handlers/user/apiTokenCreate.js +0 -71
- package/src/handlers/user/apiTokenList.js +0 -64
- package/src/handlers/user/userSplashAck.js +0 -91
- package/src/handlers/user/userSplashGet.js +0 -211
- package/src/handlers/users/cognitoPostConfirmation.js +0 -186
- package/src/handlers/users/cognitoPreSignUp.js +0 -114
- package/src/handlers/users/userEntitlementsGet.js +0 -89
- package/src/handlers/users/userGet.js +0 -118
- package/src/handlers/users/userProfilePut.js +0 -77
- 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
|
-
});
|