@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.
- package/hooks/session-start.js +312 -85
- package/package.json +21 -13
- package/scripts/init-project.js +9 -23
- package/scripts/repo-analyzer.js +118 -2
- 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/inject.js +0 -409
- package/scripts/mcp-bridge.js +0 -220
- package/scripts/standards.js +0 -285
- 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,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose Get Handler
|
|
3
|
-
* Retrieves relationship purpose for a scope
|
|
4
|
-
*
|
|
5
|
-
* GET /api/context/purpose?scope=jarvis
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, checkSuperAdmin } = require('./helpers');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Get relationship purpose
|
|
12
|
-
*/
|
|
13
|
-
async function getPurpose({ queryStringParameters: queryParams = {}, requestContext }) {
|
|
14
|
-
try {
|
|
15
|
-
const Request_ID = requestContext.requestId;
|
|
16
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
17
|
-
|
|
18
|
-
if (!email) {
|
|
19
|
-
return createErrorResponse(401, 'Unauthorized');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Gate to super admins only (internal/beta endpoint)
|
|
23
|
-
await checkSuperAdmin.requireSuperAdmin(email);
|
|
24
|
-
|
|
25
|
-
const scope = queryParams.scope || 'jarvis';
|
|
26
|
-
|
|
27
|
-
const query = `
|
|
28
|
-
SELECT
|
|
29
|
-
purpose_text,
|
|
30
|
-
confidence,
|
|
31
|
-
confirmed,
|
|
32
|
-
maturity,
|
|
33
|
-
evolution,
|
|
34
|
-
created_at,
|
|
35
|
-
updated_at
|
|
36
|
-
FROM rapport.relationship_purpose
|
|
37
|
-
WHERE email_address = $1
|
|
38
|
-
AND scope = $2
|
|
39
|
-
`;
|
|
40
|
-
const result = await executeQuery(query, [email, scope]);
|
|
41
|
-
|
|
42
|
-
if (result.rowCount === 0) {
|
|
43
|
-
return createSuccessResponse(
|
|
44
|
-
{
|
|
45
|
-
scope,
|
|
46
|
-
purpose: null,
|
|
47
|
-
message: 'No purpose defined for this scope'
|
|
48
|
-
},
|
|
49
|
-
'No purpose found',
|
|
50
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const row = result.rows[0];
|
|
55
|
-
|
|
56
|
-
return createSuccessResponse(
|
|
57
|
-
{
|
|
58
|
-
scope,
|
|
59
|
-
purpose: row.purpose_text,
|
|
60
|
-
confidence: parseFloat(row.confidence),
|
|
61
|
-
confirmed: row.confirmed,
|
|
62
|
-
maturity: row.maturity,
|
|
63
|
-
evolution: row.evolution || []
|
|
64
|
-
},
|
|
65
|
-
row.purpose_text,
|
|
66
|
-
{
|
|
67
|
-
Request_ID,
|
|
68
|
-
Timestamp: new Date().toISOString()
|
|
69
|
-
}
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.error('Handler Error:', error);
|
|
74
|
-
return handleError(error);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
exports.handler = wrapHandler(getPurpose);
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get Developer Correlations Handler
|
|
3
|
-
* Returns session-to-commit correlation data for a specific developer
|
|
4
|
-
*
|
|
5
|
-
* GET /api/correlations/developer?email=xxx
|
|
6
|
-
* Query params:
|
|
7
|
-
* - email (required)
|
|
8
|
-
* - lookbackDays (optional, default: 30)
|
|
9
|
-
*
|
|
10
|
-
* Returns:
|
|
11
|
-
* - Developer productivity metrics
|
|
12
|
-
* - Session history with commit correlation
|
|
13
|
-
* - Trend analysis
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
17
|
-
const { CorrelationAnalyzer } = require('./core/CorrelationAnalyzer');
|
|
18
|
-
|
|
19
|
-
exports.handler = wrapHandler(async (event, context) => {
|
|
20
|
-
// Extract user email from Cognito claims
|
|
21
|
-
const requestingEmail = event.requestContext?.authorizer?.claims?.email;
|
|
22
|
-
if (!requestingEmail) {
|
|
23
|
-
return createErrorResponse(401, 'Unauthorized - no email in claims');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Get target developer email from query parameters
|
|
27
|
-
const targetEmail = decodeURIComponent(event.queryStringParameters?.email || '');
|
|
28
|
-
if (!targetEmail) {
|
|
29
|
-
return createErrorResponse(400, 'Developer email is required');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Parse query parameters
|
|
33
|
-
const queryParams = event.queryStringParameters || {};
|
|
34
|
-
const lookbackDays = parseInt(queryParams.lookbackDays) || 30;
|
|
35
|
-
|
|
36
|
-
// Check if requesting own data or if admin
|
|
37
|
-
const isSelf = requestingEmail.toLowerCase() === targetEmail.toLowerCase();
|
|
38
|
-
|
|
39
|
-
if (!isSelf) {
|
|
40
|
-
// Verify requesting user is admin in a shared company
|
|
41
|
-
const accessResult = await executeQuery(`
|
|
42
|
-
SELECT DISTINCT ue1.company_id
|
|
43
|
-
FROM rapport.user_entitlements ue1
|
|
44
|
-
JOIN rapport.user_entitlements ue2 ON ue1.company_id = ue2.company_id
|
|
45
|
-
WHERE ue1.email_address = $1
|
|
46
|
-
AND ue2.email_address = $2
|
|
47
|
-
AND (ue1.admin = true OR ue1.manager = true)
|
|
48
|
-
`, [requestingEmail, targetEmail]);
|
|
49
|
-
|
|
50
|
-
if (accessResult.rows.length === 0) {
|
|
51
|
-
return createErrorResponse(403, 'Access denied - admin privileges required to view other developers');
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Get developer info
|
|
56
|
-
const developerResult = await executeQuery(`
|
|
57
|
-
SELECT
|
|
58
|
-
u.email_address as email,
|
|
59
|
-
CONCAT(u.first_name, ' ', u.last_name) as display_name,
|
|
60
|
-
u.first_name,
|
|
61
|
-
u.last_name
|
|
62
|
-
FROM rapport.users u
|
|
63
|
-
WHERE u.email_address = $1
|
|
64
|
-
`, [targetEmail]);
|
|
65
|
-
|
|
66
|
-
if (developerResult.rows.length === 0) {
|
|
67
|
-
return createErrorResponse(404, 'Developer not found');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const developer = developerResult.rows[0];
|
|
71
|
-
|
|
72
|
-
// Initialize analyzer
|
|
73
|
-
const analyzer = new CorrelationAnalyzer();
|
|
74
|
-
|
|
75
|
-
// Get developer productivity metrics
|
|
76
|
-
const productivity = await analyzer.getDeveloperProductivity(targetEmail, lookbackDays);
|
|
77
|
-
|
|
78
|
-
// Get session history
|
|
79
|
-
const sessionHistory = await getSessionHistory(targetEmail, lookbackDays, 20);
|
|
80
|
-
|
|
81
|
-
// Get weekly trend
|
|
82
|
-
const weeklyTrend = await getWeeklyTrend(targetEmail, lookbackDays);
|
|
83
|
-
|
|
84
|
-
// Get pattern usage
|
|
85
|
-
const patternUsage = await getPatternUsage(targetEmail, lookbackDays);
|
|
86
|
-
|
|
87
|
-
return createSuccessResponse({
|
|
88
|
-
developer: {
|
|
89
|
-
email: developer.email,
|
|
90
|
-
displayName: developer.display_name,
|
|
91
|
-
firstName: developer.first_name,
|
|
92
|
-
lastName: developer.last_name
|
|
93
|
-
},
|
|
94
|
-
productivity,
|
|
95
|
-
sessionHistory,
|
|
96
|
-
weeklyTrend,
|
|
97
|
-
patternUsage
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get session history for a developer
|
|
103
|
-
*/
|
|
104
|
-
async function getSessionHistory(email, lookbackDays, limit) {
|
|
105
|
-
const query = `
|
|
106
|
-
SELECT
|
|
107
|
-
sc.session_id,
|
|
108
|
-
sc.project_id,
|
|
109
|
-
p.project_name,
|
|
110
|
-
sc.session_started_at,
|
|
111
|
-
sc.session_ended_at,
|
|
112
|
-
sc.session_duration_seconds,
|
|
113
|
-
sc.has_commits,
|
|
114
|
-
sc.commit_count,
|
|
115
|
-
sc.total_insertions,
|
|
116
|
-
sc.total_deletions,
|
|
117
|
-
sc.total_files_changed,
|
|
118
|
-
sc.avg_commit_latency_minutes,
|
|
119
|
-
sc.patterns_used,
|
|
120
|
-
sc.correlation_type,
|
|
121
|
-
sc.correlation_score
|
|
122
|
-
FROM rapport.session_correlations sc
|
|
123
|
-
LEFT JOIN rapport.projects p ON sc.project_id = p.project_id
|
|
124
|
-
WHERE sc.email_address = $1
|
|
125
|
-
AND sc.session_started_at > NOW() - $2 * INTERVAL '1 day'
|
|
126
|
-
ORDER BY sc.session_started_at DESC
|
|
127
|
-
LIMIT $3
|
|
128
|
-
`;
|
|
129
|
-
|
|
130
|
-
const result = await executeQuery(query, [email, lookbackDays, limit]);
|
|
131
|
-
|
|
132
|
-
return result.rows.map(row => ({
|
|
133
|
-
sessionId: row.session_id,
|
|
134
|
-
projectId: row.project_id,
|
|
135
|
-
projectName: row.project_name,
|
|
136
|
-
startedAt: row.session_started_at,
|
|
137
|
-
endedAt: row.session_ended_at,
|
|
138
|
-
durationMinutes: Math.round((row.session_duration_seconds || 0) / 60),
|
|
139
|
-
hasCommits: row.has_commits,
|
|
140
|
-
commitCount: row.commit_count,
|
|
141
|
-
insertions: row.total_insertions,
|
|
142
|
-
deletions: row.total_deletions,
|
|
143
|
-
filesChanged: row.total_files_changed,
|
|
144
|
-
commitLatencyMinutes: row.avg_commit_latency_minutes,
|
|
145
|
-
patternsUsed: row.patterns_used,
|
|
146
|
-
correlationType: row.correlation_type,
|
|
147
|
-
correlationScore: parseFloat(row.correlation_score) || 0
|
|
148
|
-
}));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Get weekly productivity trend for a developer
|
|
153
|
-
*/
|
|
154
|
-
async function getWeeklyTrend(email, lookbackDays) {
|
|
155
|
-
const query = `
|
|
156
|
-
SELECT
|
|
157
|
-
DATE_TRUNC('week', sc.session_started_at) as week,
|
|
158
|
-
COUNT(*) as total_sessions,
|
|
159
|
-
COUNT(*) FILTER (WHERE sc.has_commits = true) as productive_sessions,
|
|
160
|
-
ROUND(
|
|
161
|
-
COUNT(*) FILTER (WHERE sc.has_commits = true)::decimal /
|
|
162
|
-
NULLIF(COUNT(*), 0) * 100,
|
|
163
|
-
1
|
|
164
|
-
) as conversion_rate,
|
|
165
|
-
SUM(sc.commit_count) as total_commits,
|
|
166
|
-
SUM(sc.total_insertions) as total_insertions,
|
|
167
|
-
SUM(sc.total_deletions) as total_deletions,
|
|
168
|
-
SUM(sc.session_duration_seconds) / 3600.0 as session_hours
|
|
169
|
-
FROM rapport.session_correlations sc
|
|
170
|
-
WHERE sc.email_address = $1
|
|
171
|
-
AND sc.session_started_at > NOW() - $2 * INTERVAL '1 day'
|
|
172
|
-
GROUP BY DATE_TRUNC('week', sc.session_started_at)
|
|
173
|
-
ORDER BY week DESC
|
|
174
|
-
`;
|
|
175
|
-
|
|
176
|
-
const result = await executeQuery(query, [email, lookbackDays]);
|
|
177
|
-
|
|
178
|
-
return result.rows.map(row => ({
|
|
179
|
-
week: row.week,
|
|
180
|
-
totalSessions: parseInt(row.total_sessions) || 0,
|
|
181
|
-
productiveSessions: parseInt(row.productive_sessions) || 0,
|
|
182
|
-
conversionRate: parseFloat(row.conversion_rate) || 0,
|
|
183
|
-
totalCommits: parseInt(row.total_commits) || 0,
|
|
184
|
-
totalInsertions: parseInt(row.total_insertions) || 0,
|
|
185
|
-
totalDeletions: parseInt(row.total_deletions) || 0,
|
|
186
|
-
sessionHours: parseFloat(row.session_hours) || 0
|
|
187
|
-
}));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Get pattern usage statistics for a developer
|
|
192
|
-
*/
|
|
193
|
-
async function getPatternUsage(email, lookbackDays) {
|
|
194
|
-
const query = `
|
|
195
|
-
SELECT
|
|
196
|
-
p.pattern_id,
|
|
197
|
-
p.intent,
|
|
198
|
-
p.maturity,
|
|
199
|
-
COUNT(DISTINCT pu.session_id) as sessions_used,
|
|
200
|
-
COUNT(DISTINCT sc.session_id) FILTER (WHERE sc.has_commits = true) as sessions_with_commits,
|
|
201
|
-
ROUND(
|
|
202
|
-
COUNT(DISTINCT sc.session_id) FILTER (WHERE sc.has_commits = true)::decimal /
|
|
203
|
-
NULLIF(COUNT(DISTINCT pu.session_id), 0) * 100,
|
|
204
|
-
1
|
|
205
|
-
) as pattern_conversion_rate
|
|
206
|
-
FROM rapport.pattern_usage pu
|
|
207
|
-
JOIN rapport.patterns p ON pu.pattern_id = p.pattern_id
|
|
208
|
-
LEFT JOIN rapport.session_correlations sc ON pu.session_id = sc.session_id
|
|
209
|
-
WHERE pu.email_address = $1
|
|
210
|
-
AND pu.used_at > NOW() - $2 * INTERVAL '1 day'
|
|
211
|
-
GROUP BY p.pattern_id, p.intent, p.maturity
|
|
212
|
-
HAVING COUNT(DISTINCT pu.session_id) >= 2
|
|
213
|
-
ORDER BY sessions_used DESC
|
|
214
|
-
LIMIT 10
|
|
215
|
-
`;
|
|
216
|
-
|
|
217
|
-
const result = await executeQuery(query, [email, lookbackDays]);
|
|
218
|
-
|
|
219
|
-
return result.rows.map(row => ({
|
|
220
|
-
patternId: row.pattern_id,
|
|
221
|
-
intent: row.intent,
|
|
222
|
-
maturity: row.maturity,
|
|
223
|
-
sessionsUsed: parseInt(row.sessions_used) || 0,
|
|
224
|
-
sessionsWithCommits: parseInt(row.sessions_with_commits) || 0,
|
|
225
|
-
patternConversionRate: parseFloat(row.pattern_conversion_rate) || 0
|
|
226
|
-
}));
|
|
227
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get Correlations Handler
|
|
3
|
-
* Returns session-to-commit correlation summary for a company
|
|
4
|
-
*
|
|
5
|
-
* GET /api/correlations
|
|
6
|
-
* Query params:
|
|
7
|
-
* - lookbackDays (optional, default: 30)
|
|
8
|
-
*
|
|
9
|
-
* Returns:
|
|
10
|
-
* - Overall correlation summary
|
|
11
|
-
* - Conversion rate metrics
|
|
12
|
-
* - Correlation type distribution
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
16
|
-
const { CorrelationAnalyzer } = require('./core/CorrelationAnalyzer');
|
|
17
|
-
|
|
18
|
-
exports.handler = wrapHandler(async (event, context) => {
|
|
19
|
-
// Extract user email from Cognito claims
|
|
20
|
-
const email = event.requestContext?.authorizer?.claims?.email;
|
|
21
|
-
if (!email) {
|
|
22
|
-
return createErrorResponse(401, 'Unauthorized - no email in claims');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Parse query parameters
|
|
26
|
-
const queryParams = event.queryStringParameters || {};
|
|
27
|
-
const lookbackDays = parseInt(queryParams.lookbackDays) || 30;
|
|
28
|
-
|
|
29
|
-
// Get user's company
|
|
30
|
-
const companyResult = await executeQuery(`
|
|
31
|
-
SELECT ue.company_id
|
|
32
|
-
FROM rapport.user_entitlements ue
|
|
33
|
-
WHERE ue.email_address = $1
|
|
34
|
-
LIMIT 1
|
|
35
|
-
`, [email]);
|
|
36
|
-
|
|
37
|
-
if (companyResult.rows.length === 0) {
|
|
38
|
-
return createErrorResponse(403, 'User not associated with any company');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const companyId = companyResult.rows[0].company_id;
|
|
42
|
-
|
|
43
|
-
// Initialize analyzer
|
|
44
|
-
const analyzer = new CorrelationAnalyzer();
|
|
45
|
-
|
|
46
|
-
// Get correlation summary
|
|
47
|
-
let summary = null;
|
|
48
|
-
let patternEffectiveness = [];
|
|
49
|
-
let strugglingDevelopers = [];
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
summary = await analyzer.getCorrelationSummary(companyId, lookbackDays);
|
|
53
|
-
} catch (err) {
|
|
54
|
-
console.error('Error getting correlation summary:', err.message);
|
|
55
|
-
summary = { error: err.message };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
patternEffectiveness = await analyzer.getPatternEffectiveness(null, lookbackDays);
|
|
60
|
-
} catch (err) {
|
|
61
|
-
console.error('Error getting pattern effectiveness:', err.message);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Get struggling developers (for admins only)
|
|
65
|
-
try {
|
|
66
|
-
const isAdmin = await checkIsAdmin(email, companyId);
|
|
67
|
-
if (isAdmin) {
|
|
68
|
-
strugglingDevelopers = await analyzer.identifyStrugglingDevelopers(companyId, lookbackDays);
|
|
69
|
-
}
|
|
70
|
-
} catch (err) {
|
|
71
|
-
console.error('Error getting struggling developers:', err.message);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return createSuccessResponse({
|
|
75
|
-
summary,
|
|
76
|
-
patternEffectiveness,
|
|
77
|
-
strugglingDevelopers
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Check if user is admin for the company
|
|
83
|
-
*/
|
|
84
|
-
async function checkIsAdmin(email, companyId) {
|
|
85
|
-
const result = await executeQuery(`
|
|
86
|
-
SELECT admin, manager
|
|
87
|
-
FROM rapport.user_entitlements
|
|
88
|
-
WHERE email_address = $1 AND company_id = $2
|
|
89
|
-
`, [email, companyId]);
|
|
90
|
-
|
|
91
|
-
if (result.rows.length === 0) return false;
|
|
92
|
-
return result.rows[0].admin || result.rows[0].manager;
|
|
93
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get Project Correlations Handler
|
|
3
|
-
* Returns session-to-commit correlation data for a specific project
|
|
4
|
-
*
|
|
5
|
-
* GET /api/correlations/project?project_id=xxx
|
|
6
|
-
* Query params:
|
|
7
|
-
* - project_id (required)
|
|
8
|
-
* - lookbackDays (optional, default: 30)
|
|
9
|
-
*
|
|
10
|
-
* Returns:
|
|
11
|
-
* - Project productivity metrics
|
|
12
|
-
* - Developer breakdown
|
|
13
|
-
* - Pattern effectiveness for project
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, verifyProjectAccess } = require('./helpers');
|
|
17
|
-
const { CorrelationAnalyzer } = require('./core/CorrelationAnalyzer');
|
|
18
|
-
|
|
19
|
-
exports.handler = wrapHandler(async (event, context) => {
|
|
20
|
-
// Extract user email from Cognito claims
|
|
21
|
-
const email = event.requestContext?.authorizer?.claims?.email;
|
|
22
|
-
if (!email) {
|
|
23
|
-
return createErrorResponse(401, 'Unauthorized - no email in claims');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Get project ID from query parameters
|
|
27
|
-
const projectId = event.queryStringParameters?.project_id;
|
|
28
|
-
if (!projectId) {
|
|
29
|
-
return createErrorResponse(400, 'Project ID is required');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Parse query parameters
|
|
33
|
-
const queryParams = event.queryStringParameters || {};
|
|
34
|
-
const lookbackDays = parseInt(queryParams.lookbackDays) || 30;
|
|
35
|
-
|
|
36
|
-
// Verify user has access to this project (collaborator or company member)
|
|
37
|
-
const project = await verifyProjectAccess(projectId, email);
|
|
38
|
-
if (!project) {
|
|
39
|
-
return createErrorResponse(403, 'Access denied to this project');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Initialize analyzer
|
|
43
|
-
const analyzer = new CorrelationAnalyzer();
|
|
44
|
-
|
|
45
|
-
// Get project productivity metrics
|
|
46
|
-
const projectMetrics = await analyzer.getProjectProductivity(projectId, lookbackDays);
|
|
47
|
-
|
|
48
|
-
// Get developer breakdown for the project
|
|
49
|
-
const developerBreakdown = await getDeveloperBreakdown(projectId, lookbackDays);
|
|
50
|
-
|
|
51
|
-
// Get pattern effectiveness for this project
|
|
52
|
-
const patternEffectiveness = await analyzer.getPatternEffectiveness(projectId, lookbackDays);
|
|
53
|
-
|
|
54
|
-
// Get recent correlations
|
|
55
|
-
const recentCorrelations = await getRecentCorrelations(projectId, 10);
|
|
56
|
-
|
|
57
|
-
return createSuccessResponse({
|
|
58
|
-
project: {
|
|
59
|
-
projectId: project.project_id,
|
|
60
|
-
projectName: project.project_name,
|
|
61
|
-
companyId: project.company_id
|
|
62
|
-
},
|
|
63
|
-
metrics: projectMetrics,
|
|
64
|
-
developerBreakdown,
|
|
65
|
-
patternEffectiveness,
|
|
66
|
-
recentCorrelations
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get developer breakdown for a project
|
|
72
|
-
*/
|
|
73
|
-
async function getDeveloperBreakdown(projectId, lookbackDays) {
|
|
74
|
-
const query = `
|
|
75
|
-
SELECT
|
|
76
|
-
sc.email_address,
|
|
77
|
-
CONCAT(u.first_name, ' ', u.last_name) as display_name,
|
|
78
|
-
COUNT(*) as total_sessions,
|
|
79
|
-
COUNT(*) FILTER (WHERE sc.has_commits = true) as productive_sessions,
|
|
80
|
-
ROUND(
|
|
81
|
-
COUNT(*) FILTER (WHERE sc.has_commits = true)::decimal /
|
|
82
|
-
NULLIF(COUNT(*), 0) * 100,
|
|
83
|
-
1
|
|
84
|
-
) as conversion_rate,
|
|
85
|
-
SUM(sc.commit_count) as total_commits,
|
|
86
|
-
SUM(sc.total_insertions) as total_insertions,
|
|
87
|
-
SUM(sc.total_deletions) as total_deletions,
|
|
88
|
-
ROUND(AVG(sc.session_duration_seconds) / 60, 0) as avg_session_minutes,
|
|
89
|
-
MAX(sc.session_started_at) as last_session
|
|
90
|
-
FROM rapport.session_correlations sc
|
|
91
|
-
JOIN rapport.users u ON sc.email_address = u.email_address
|
|
92
|
-
WHERE sc.project_id = $1
|
|
93
|
-
AND sc.session_started_at > NOW() - $2 * INTERVAL '1 day'
|
|
94
|
-
GROUP BY sc.email_address, u.first_name, u.last_name
|
|
95
|
-
ORDER BY total_commits DESC NULLS LAST
|
|
96
|
-
`;
|
|
97
|
-
|
|
98
|
-
const result = await executeQuery(query, [projectId, lookbackDays]);
|
|
99
|
-
|
|
100
|
-
return result.rows.map(row => ({
|
|
101
|
-
email: row.email_address,
|
|
102
|
-
displayName: row.display_name,
|
|
103
|
-
totalSessions: parseInt(row.total_sessions) || 0,
|
|
104
|
-
productiveSessions: parseInt(row.productive_sessions) || 0,
|
|
105
|
-
conversionRate: parseFloat(row.conversion_rate) || 0,
|
|
106
|
-
totalCommits: parseInt(row.total_commits) || 0,
|
|
107
|
-
totalInsertions: parseInt(row.total_insertions) || 0,
|
|
108
|
-
totalDeletions: parseInt(row.total_deletions) || 0,
|
|
109
|
-
avgSessionMinutes: parseInt(row.avg_session_minutes) || 0,
|
|
110
|
-
lastSession: row.last_session
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Get recent correlations for a project
|
|
116
|
-
*/
|
|
117
|
-
async function getRecentCorrelations(projectId, limit) {
|
|
118
|
-
const query = `
|
|
119
|
-
SELECT
|
|
120
|
-
sc.session_id,
|
|
121
|
-
sc.email_address,
|
|
122
|
-
CONCAT(u.first_name, ' ', u.last_name) as display_name,
|
|
123
|
-
sc.session_started_at,
|
|
124
|
-
sc.session_duration_seconds,
|
|
125
|
-
sc.has_commits,
|
|
126
|
-
sc.commit_count,
|
|
127
|
-
sc.total_insertions,
|
|
128
|
-
sc.total_deletions,
|
|
129
|
-
sc.correlation_type,
|
|
130
|
-
sc.correlation_score
|
|
131
|
-
FROM rapport.session_correlations sc
|
|
132
|
-
JOIN rapport.users u ON sc.email_address = u.email_address
|
|
133
|
-
WHERE sc.project_id = $1
|
|
134
|
-
ORDER BY sc.session_started_at DESC
|
|
135
|
-
LIMIT $2
|
|
136
|
-
`;
|
|
137
|
-
|
|
138
|
-
const result = await executeQuery(query, [projectId, limit]);
|
|
139
|
-
|
|
140
|
-
return result.rows.map(row => ({
|
|
141
|
-
sessionId: row.session_id,
|
|
142
|
-
email: row.email_address,
|
|
143
|
-
displayName: row.display_name,
|
|
144
|
-
sessionStarted: row.session_started_at,
|
|
145
|
-
sessionDurationMinutes: Math.round((row.session_duration_seconds || 0) / 60),
|
|
146
|
-
hasCommits: row.has_commits,
|
|
147
|
-
commitCount: row.commit_count,
|
|
148
|
-
totalInsertions: row.total_insertions,
|
|
149
|
-
totalDeletions: row.total_deletions,
|
|
150
|
-
correlationType: row.correlation_type,
|
|
151
|
-
correlationScore: parseFloat(row.correlation_score) || 0
|
|
152
|
-
}));
|
|
153
|
-
}
|