@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,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Token Create Handler
|
|
3
|
-
*
|
|
4
|
-
* Creates a new MCP API token for the authenticated user.
|
|
5
|
-
* Token plaintext is returned ONCE — only the SHA-256 hash is stored.
|
|
6
|
-
*
|
|
7
|
-
* POST /api/user/api-tokens
|
|
8
|
-
* Auth: Cognito JWT required
|
|
9
|
-
* Body: { name?: string }
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
13
|
-
const crypto = require('crypto');
|
|
14
|
-
|
|
15
|
-
async function apiTokenCreate({ body, requestContext }) {
|
|
16
|
-
const email = requestContext.authorizer?.claims?.email
|
|
17
|
-
|| requestContext.authorizer?.jwt?.claims?.email;
|
|
18
|
-
|
|
19
|
-
if (!email) {
|
|
20
|
-
return createErrorResponse(401, 'Authentication required');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const tokenName = body.name || 'Default';
|
|
24
|
-
|
|
25
|
-
// Look up user's client and company
|
|
26
|
-
const userResult = await executeQuery(`
|
|
27
|
-
SELECT u.client_id, ue.company_id
|
|
28
|
-
FROM rapport.users u
|
|
29
|
-
LEFT JOIN rapport.user_entitlements ue ON u.email_address = ue.email_address
|
|
30
|
-
WHERE u.email_address = $1
|
|
31
|
-
LIMIT 1
|
|
32
|
-
`, [email]);
|
|
33
|
-
|
|
34
|
-
if (userResult.rows.length === 0) {
|
|
35
|
-
return createErrorResponse(404, 'User not found');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const { client_id, company_id } = userResult.rows[0];
|
|
39
|
-
|
|
40
|
-
// Verify active subscription
|
|
41
|
-
const clientResult = await executeQuery(
|
|
42
|
-
'SELECT subscription_tier FROM rapport.clients WHERE client_id = $1',
|
|
43
|
-
[client_id]
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
if (clientResult.rows.length === 0 || !clientResult.rows[0].subscription_tier || clientResult.rows[0].subscription_tier === 'free') {
|
|
47
|
-
return createErrorResponse(403, 'Active MindMeld subscription required to create API tokens');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Generate token: mm_live_ + 40 random hex chars
|
|
51
|
-
const tokenId = crypto.randomUUID();
|
|
52
|
-
const tokenRandom = crypto.randomBytes(20).toString('hex');
|
|
53
|
-
const plaintext = `mm_live_${tokenRandom}`;
|
|
54
|
-
const tokenPrefix = plaintext.substring(0, 12);
|
|
55
|
-
const tokenHash = crypto.createHash('sha256').update(plaintext).digest('hex');
|
|
56
|
-
|
|
57
|
-
await executeQuery(`
|
|
58
|
-
INSERT INTO rapport.api_tokens (token_id, token_hash, token_prefix, email_address, client_id, company_id, token_name)
|
|
59
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
60
|
-
`, [tokenId, tokenHash, tokenPrefix, email, client_id, company_id || null, tokenName]);
|
|
61
|
-
|
|
62
|
-
return createSuccessResponse({
|
|
63
|
-
token_id: tokenId,
|
|
64
|
-
token: plaintext,
|
|
65
|
-
token_prefix: tokenPrefix,
|
|
66
|
-
name: tokenName,
|
|
67
|
-
message: 'Save this token — it will not be shown again.'
|
|
68
|
-
}, 'API token created');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
exports.handler = wrapHandler(apiTokenCreate);
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Token List/Revoke Handler
|
|
3
|
-
*
|
|
4
|
-
* GET /api/user/api-tokens — List tokens (prefix only, never plaintext)
|
|
5
|
-
* DELETE /api/user/api-tokens?token_id=xxx — Revoke a token
|
|
6
|
-
*
|
|
7
|
-
* Auth: Cognito JWT required
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
11
|
-
|
|
12
|
-
async function apiTokenList({ body, queryParams, requestContext, httpMethod }) {
|
|
13
|
-
const email = requestContext.authorizer?.claims?.email
|
|
14
|
-
|| requestContext.authorizer?.jwt?.claims?.email;
|
|
15
|
-
|
|
16
|
-
if (!email) {
|
|
17
|
-
return createErrorResponse(401, 'Authentication required');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// DELETE — revoke a token
|
|
21
|
-
if (httpMethod === 'DELETE') {
|
|
22
|
-
const tokenId = queryParams.token_id || body.token_id;
|
|
23
|
-
if (!tokenId) {
|
|
24
|
-
return createErrorResponse(400, 'token_id is required');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const result = await executeQuery(`
|
|
28
|
-
UPDATE rapport.api_tokens
|
|
29
|
-
SET status = 'revoked', revoked_at = NOW()
|
|
30
|
-
WHERE token_id = $1 AND email_address = $2 AND status = 'active'
|
|
31
|
-
RETURNING token_id
|
|
32
|
-
`, [tokenId, email]);
|
|
33
|
-
|
|
34
|
-
if (result.rows.length === 0) {
|
|
35
|
-
return createErrorResponse(404, 'Token not found or already revoked');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return createSuccessResponse({ token_id: tokenId }, 'Token revoked');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// GET — list tokens
|
|
42
|
-
const result = await executeQuery(`
|
|
43
|
-
SELECT token_id, token_prefix, token_name, status,
|
|
44
|
-
last_used_at, request_count, created_at, revoked_at
|
|
45
|
-
FROM rapport.api_tokens
|
|
46
|
-
WHERE email_address = $1
|
|
47
|
-
ORDER BY created_at DESC
|
|
48
|
-
`, [email]);
|
|
49
|
-
|
|
50
|
-
return createSuccessResponse({
|
|
51
|
-
tokens: result.rows.map(r => ({
|
|
52
|
-
token_id: r.token_id,
|
|
53
|
-
prefix: r.token_prefix,
|
|
54
|
-
name: r.token_name,
|
|
55
|
-
status: r.status,
|
|
56
|
-
last_used: r.last_used_at,
|
|
57
|
-
request_count: r.request_count,
|
|
58
|
-
created_at: r.created_at,
|
|
59
|
-
revoked_at: r.revoked_at
|
|
60
|
-
}))
|
|
61
|
-
}, `${result.rows.length} token(s) found`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
exports.handler = wrapHandler(apiTokenList);
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Splash Acknowledge Handler
|
|
3
|
-
* Records that the user has dismissed the weekly splash screen
|
|
4
|
-
*
|
|
5
|
-
* POST /api/user/splash/acknowledge
|
|
6
|
-
* Auth: Cognito JWT required
|
|
7
|
-
*
|
|
8
|
-
* Body: { week_start: "2026-01-27" }
|
|
9
|
-
* Records acknowledgment so splash does not show again this week
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
|
|
13
|
-
|
|
14
|
-
async function acknowledgeUserSplash({ requestContext, body }) {
|
|
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, 'Authentication required');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const weekStart = body?.week_start;
|
|
23
|
-
if (!weekStart) {
|
|
24
|
-
return createErrorResponse(400, 'week_start is required');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Validate week_start format (YYYY-MM-DD)
|
|
28
|
-
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
29
|
-
if (!dateRegex.test(weekStart)) {
|
|
30
|
-
return createErrorResponse(400, 'week_start must be in YYYY-MM-DD format');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Attempt to insert acknowledgment into dedicated table
|
|
34
|
-
try {
|
|
35
|
-
await executeQuery(`
|
|
36
|
-
INSERT INTO rapport.user_splash_acknowledgments (email_address, week_start, acknowledged_at)
|
|
37
|
-
VALUES ($1, $2, NOW())
|
|
38
|
-
ON CONFLICT (email_address, week_start) DO NOTHING
|
|
39
|
-
`, [email, weekStart]);
|
|
40
|
-
|
|
41
|
-
return createSuccessResponse(
|
|
42
|
-
{ acknowledged: true, week_start: weekStart },
|
|
43
|
-
'Splash acknowledged',
|
|
44
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
45
|
-
);
|
|
46
|
-
} catch (tableErr) {
|
|
47
|
-
// If the dedicated table does not exist, fall back to storing
|
|
48
|
-
// acknowledgment as metadata in the patterns table
|
|
49
|
-
console.log('[SplashAck] Dedicated table not available, using fallback:', tableErr.message);
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
await executeQuery(`
|
|
53
|
-
INSERT INTO rapport.patterns (
|
|
54
|
-
pattern_type,
|
|
55
|
-
pattern_key,
|
|
56
|
-
pattern_value,
|
|
57
|
-
created_by,
|
|
58
|
-
created_at,
|
|
59
|
-
metadata
|
|
60
|
-
)
|
|
61
|
-
VALUES (
|
|
62
|
-
'splash_ack',
|
|
63
|
-
$1,
|
|
64
|
-
$2,
|
|
65
|
-
$3,
|
|
66
|
-
NOW(),
|
|
67
|
-
$4
|
|
68
|
-
)
|
|
69
|
-
ON CONFLICT (pattern_type, pattern_key) WHERE pattern_type = 'splash_ack'
|
|
70
|
-
DO UPDATE SET
|
|
71
|
-
pattern_value = EXCLUDED.pattern_value,
|
|
72
|
-
created_at = NOW()
|
|
73
|
-
`, [
|
|
74
|
-
`splash_ack:${email}:${weekStart}`,
|
|
75
|
-
weekStart,
|
|
76
|
-
email,
|
|
77
|
-
JSON.stringify({ type: 'splash_acknowledgment', week_start: weekStart })
|
|
78
|
-
]);
|
|
79
|
-
|
|
80
|
-
return createSuccessResponse(
|
|
81
|
-
{ acknowledged: true, week_start: weekStart, fallback: true },
|
|
82
|
-
'Splash acknowledged (fallback)',
|
|
83
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
84
|
-
);
|
|
85
|
-
} catch (fallbackErr) {
|
|
86
|
-
return handleError(fallbackErr);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
exports.handler = wrapHandler(acknowledgeUserSplash);
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User Splash Get Handler
|
|
3
|
-
* Returns weekly activity summary for the splash screen overlay
|
|
4
|
-
*
|
|
5
|
-
* GET /api/user/splash
|
|
6
|
-
* Auth: Cognito JWT required
|
|
7
|
-
*
|
|
8
|
-
* Returns:
|
|
9
|
-
* - show_splash: whether to display the splash (false if already acknowledged this week)
|
|
10
|
-
* - summary: weekly activity metrics from sessions + session_standards
|
|
11
|
-
* - is_greenfield: true if user has < 7 days of session history
|
|
12
|
-
* - tips: getting-started tips for greenfield users
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
|
|
16
|
-
|
|
17
|
-
async function getUserSplash({ requestContext }) {
|
|
18
|
-
const Request_ID = requestContext.requestId;
|
|
19
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
20
|
-
|
|
21
|
-
if (!email) {
|
|
22
|
-
return createErrorResponse(401, 'Authentication required');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Calculate current week boundaries (Monday to Sunday UTC)
|
|
26
|
-
const now = new Date();
|
|
27
|
-
const dayOfWeek = now.getUTCDay();
|
|
28
|
-
const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
|
|
29
|
-
const weekStart = new Date(now);
|
|
30
|
-
weekStart.setUTCDate(now.getUTCDate() + mondayOffset);
|
|
31
|
-
weekStart.setUTCHours(0, 0, 0, 0);
|
|
32
|
-
|
|
33
|
-
const weekEnd = new Date(weekStart);
|
|
34
|
-
weekEnd.setUTCDate(weekStart.getUTCDate() + 6);
|
|
35
|
-
weekEnd.setUTCHours(23, 59, 59, 999);
|
|
36
|
-
|
|
37
|
-
const weekStartStr = weekStart.toISOString().split('T')[0];
|
|
38
|
-
const weekEndStr = weekEnd.toISOString().split('T')[0];
|
|
39
|
-
|
|
40
|
-
// Check if user has already acknowledged the splash this week
|
|
41
|
-
let alreadyAcknowledged = false;
|
|
42
|
-
try {
|
|
43
|
-
const ackResult = await executeQuery(`
|
|
44
|
-
SELECT 1
|
|
45
|
-
FROM rapport.user_splash_acknowledgments
|
|
46
|
-
WHERE email_address = $1
|
|
47
|
-
AND week_start = $2
|
|
48
|
-
LIMIT 1
|
|
49
|
-
`, [email, weekStartStr]);
|
|
50
|
-
|
|
51
|
-
alreadyAcknowledged = ackResult.rowCount > 0;
|
|
52
|
-
} catch (err) {
|
|
53
|
-
// Table may not exist yet; treat as not acknowledged
|
|
54
|
-
console.log('[Splash] Acknowledgment table not found, continuing:', err.message);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (alreadyAcknowledged) {
|
|
58
|
-
return createSuccessResponse(
|
|
59
|
-
{ show_splash: false },
|
|
60
|
-
'Splash already acknowledged this week',
|
|
61
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Determine if user is greenfield (< 7 days of session history)
|
|
66
|
-
let isGreenfield = true;
|
|
67
|
-
try {
|
|
68
|
-
const activityCheck = await executeQuery(`
|
|
69
|
-
SELECT MIN(started_at) as first_session
|
|
70
|
-
FROM rapport.sessions
|
|
71
|
-
WHERE email_address = $1
|
|
72
|
-
`, [email]);
|
|
73
|
-
|
|
74
|
-
if (activityCheck.rowCount > 0 && activityCheck.rows[0].first_session) {
|
|
75
|
-
const firstSession = new Date(activityCheck.rows[0].first_session);
|
|
76
|
-
const daysSinceFirst = Math.floor((now.getTime() - firstSession.getTime()) / (1000 * 60 * 60 * 24));
|
|
77
|
-
isGreenfield = daysSinceFirst < 7;
|
|
78
|
-
}
|
|
79
|
-
} catch (err) {
|
|
80
|
-
console.log('[Splash] Could not determine greenfield status:', err.message);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Aggregate weekly metrics from sessions + session_standards
|
|
84
|
-
const weekStartISO = weekStart.toISOString();
|
|
85
|
-
const weekEndISO = weekEnd.toISOString();
|
|
86
|
-
|
|
87
|
-
// Session stats (count, duration, projects)
|
|
88
|
-
let sessionsCount = 0;
|
|
89
|
-
let totalDurationMinutes = 0;
|
|
90
|
-
let activeProjects = 0;
|
|
91
|
-
try {
|
|
92
|
-
const sessionResult = await executeQuery(`
|
|
93
|
-
SELECT
|
|
94
|
-
COUNT(*) as session_count,
|
|
95
|
-
COALESCE(ROUND(SUM(duration_seconds) / 60.0), 0) as total_minutes,
|
|
96
|
-
COUNT(DISTINCT project_id) as project_count
|
|
97
|
-
FROM rapport.sessions
|
|
98
|
-
WHERE email_address = $1
|
|
99
|
-
AND started_at >= $2
|
|
100
|
-
AND started_at <= $3
|
|
101
|
-
`, [email, weekStartISO, weekEndISO]);
|
|
102
|
-
|
|
103
|
-
if (sessionResult.rowCount > 0) {
|
|
104
|
-
sessionsCount = parseInt(sessionResult.rows[0].session_count, 10) || 0;
|
|
105
|
-
totalDurationMinutes = parseInt(sessionResult.rows[0].total_minutes, 10) || 0;
|
|
106
|
-
activeProjects = parseInt(sessionResult.rows[0].project_count, 10) || 0;
|
|
107
|
-
}
|
|
108
|
-
} catch (err) {
|
|
109
|
-
console.log('[Splash] Session stats query failed:', err.message);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Standards stats (injected, followed, violated)
|
|
113
|
-
let standardsInjected = 0;
|
|
114
|
-
let standardsFollowed = 0;
|
|
115
|
-
let violationsDetected = 0;
|
|
116
|
-
try {
|
|
117
|
-
const standardsResult = await executeQuery(`
|
|
118
|
-
SELECT
|
|
119
|
-
COUNT(*) as total_injected,
|
|
120
|
-
COUNT(*) FILTER (WHERE ss.followed = true) as total_followed,
|
|
121
|
-
COUNT(*) FILTER (WHERE ss.violated = true) as total_violated
|
|
122
|
-
FROM rapport.session_standards ss
|
|
123
|
-
JOIN rapport.sessions s ON s.session_id = ss.session_id
|
|
124
|
-
WHERE s.email_address = $1
|
|
125
|
-
AND s.started_at >= $2
|
|
126
|
-
AND s.started_at <= $3
|
|
127
|
-
`, [email, weekStartISO, weekEndISO]);
|
|
128
|
-
|
|
129
|
-
if (standardsResult.rowCount > 0) {
|
|
130
|
-
standardsInjected = parseInt(standardsResult.rows[0].total_injected, 10) || 0;
|
|
131
|
-
standardsFollowed = parseInt(standardsResult.rows[0].total_followed, 10) || 0;
|
|
132
|
-
violationsDetected = parseInt(standardsResult.rows[0].total_violated, 10) || 0;
|
|
133
|
-
}
|
|
134
|
-
} catch (err) {
|
|
135
|
-
console.log('[Splash] Standards stats query failed:', err.message);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Patterns harvested (keep existing query — patterns table exists)
|
|
139
|
-
let patternsHarvested = 0;
|
|
140
|
-
try {
|
|
141
|
-
const patternsResult = await executeQuery(`
|
|
142
|
-
SELECT COUNT(*) as count
|
|
143
|
-
FROM rapport.patterns
|
|
144
|
-
WHERE created_by = $1
|
|
145
|
-
AND created_at >= $2
|
|
146
|
-
AND created_at <= $3
|
|
147
|
-
`, [email, weekStartISO, weekEndISO]);
|
|
148
|
-
|
|
149
|
-
patternsHarvested = parseInt(patternsResult.rows[0].count, 10) || 0;
|
|
150
|
-
} catch (err) {
|
|
151
|
-
console.log('[Splash] Patterns query failed:', err.message);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Recent category distribution (what the user has been working on)
|
|
155
|
-
let recentCategories = {};
|
|
156
|
-
try {
|
|
157
|
-
const categoryResult = await executeQuery(`
|
|
158
|
-
SELECT sp.category, COUNT(*) as usage_count
|
|
159
|
-
FROM rapport.session_standards ss
|
|
160
|
-
JOIN rapport.sessions s ON s.session_id = ss.session_id
|
|
161
|
-
JOIN rapport.standards_patterns sp ON sp.pattern_id = ss.standard_id
|
|
162
|
-
WHERE s.email_address = $1
|
|
163
|
-
AND s.started_at >= $2
|
|
164
|
-
AND s.started_at <= $3
|
|
165
|
-
GROUP BY sp.category
|
|
166
|
-
ORDER BY usage_count DESC
|
|
167
|
-
LIMIT 5
|
|
168
|
-
`, [email, weekStartISO, weekEndISO]);
|
|
169
|
-
|
|
170
|
-
for (const row of categoryResult.rows) {
|
|
171
|
-
recentCategories[row.category] = parseInt(row.usage_count, 10);
|
|
172
|
-
}
|
|
173
|
-
} catch (err) {
|
|
174
|
-
console.log('[Splash] Recent categories query failed:', err.message);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Build tips for greenfield users
|
|
178
|
-
const tips = isGreenfield ? [
|
|
179
|
-
'MindMeld automatically injects relevant standards into your AI coding sessions.',
|
|
180
|
-
'Use /mm-load <domain> to pre-load standards before starting work (e.g., /mm-load Frontend).',
|
|
181
|
-
'Use /mm-workflows to see available step-by-step procedures.',
|
|
182
|
-
'Patterns discovered in your code can be promoted to team-wide standards.',
|
|
183
|
-
'Use /mm-status to check your system health and API connectivity.'
|
|
184
|
-
] : [];
|
|
185
|
-
|
|
186
|
-
const summary = {
|
|
187
|
-
sessions_count: sessionsCount,
|
|
188
|
-
total_duration_minutes: totalDurationMinutes,
|
|
189
|
-
standards_injected: standardsInjected,
|
|
190
|
-
standards_followed: standardsFollowed,
|
|
191
|
-
violations_detected: violationsDetected,
|
|
192
|
-
active_projects: activeProjects,
|
|
193
|
-
recent_categories: recentCategories,
|
|
194
|
-
patterns_harvested: patternsHarvested,
|
|
195
|
-
week_start: weekStartStr,
|
|
196
|
-
week_end: weekEndStr
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
return createSuccessResponse(
|
|
200
|
-
{
|
|
201
|
-
show_splash: true,
|
|
202
|
-
summary,
|
|
203
|
-
is_greenfield: isGreenfield,
|
|
204
|
-
tips
|
|
205
|
-
},
|
|
206
|
-
'Splash data retrieved',
|
|
207
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
exports.handler = wrapHandler(getUserSplash);
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cognito Post-Confirmation Handler
|
|
3
|
-
* Creates user record and personal workspace after email verification
|
|
4
|
-
*
|
|
5
|
-
* Triggered by: Cognito User Pool post-confirmation trigger
|
|
6
|
-
* Following: cognito_authentication_standards.md
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { executeQuery } = require('./helpers');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Handle post-confirmation trigger
|
|
13
|
-
* Creates user, personal client, personal company, and entitlement
|
|
14
|
-
*/
|
|
15
|
-
async function handler(event, context) {
|
|
16
|
-
console.log('Post-confirmation trigger:', JSON.stringify(event, null, 2));
|
|
17
|
-
|
|
18
|
-
// Only process SignUp confirmations
|
|
19
|
-
if (event.triggerSource !== 'PostConfirmation_ConfirmSignUp') {
|
|
20
|
-
console.log('Skipping trigger source:', event.triggerSource);
|
|
21
|
-
return event;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const { userName, request } = event;
|
|
25
|
-
const { userAttributes } = request;
|
|
26
|
-
|
|
27
|
-
const email = userAttributes.email;
|
|
28
|
-
const cognitoSub = userAttributes.sub;
|
|
29
|
-
const firstName = userAttributes.given_name || '';
|
|
30
|
-
const lastName = userAttributes.family_name || '';
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
await executeQuery('BEGIN');
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
// 1. Create user record
|
|
37
|
-
const userQuery = `
|
|
38
|
-
INSERT INTO rapport.users (
|
|
39
|
-
email_address,
|
|
40
|
-
cognito_sub,
|
|
41
|
-
first_name,
|
|
42
|
-
last_name,
|
|
43
|
-
client_id,
|
|
44
|
-
user_status,
|
|
45
|
-
active
|
|
46
|
-
)
|
|
47
|
-
VALUES ($1, $2, $3, $4, $5, 'Active', true)
|
|
48
|
-
ON CONFLICT (email_address) DO UPDATE SET
|
|
49
|
-
cognito_sub = EXCLUDED.cognito_sub,
|
|
50
|
-
first_name = EXCLUDED.first_name,
|
|
51
|
-
last_name = EXCLUDED.last_name,
|
|
52
|
-
last_updated = CURRENT_TIMESTAMP
|
|
53
|
-
RETURNING email_address
|
|
54
|
-
`;
|
|
55
|
-
|
|
56
|
-
// Personal client ID based on email (sanitized)
|
|
57
|
-
const personalClientId = `personal_${email.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase()}`;
|
|
58
|
-
|
|
59
|
-
await executeQuery(userQuery, [
|
|
60
|
-
email,
|
|
61
|
-
cognitoSub,
|
|
62
|
-
firstName,
|
|
63
|
-
lastName,
|
|
64
|
-
personalClientId
|
|
65
|
-
]);
|
|
66
|
-
|
|
67
|
-
console.log('User created/updated:', email);
|
|
68
|
-
|
|
69
|
-
// 2. Create personal client (free tier)
|
|
70
|
-
const clientQuery = `
|
|
71
|
-
INSERT INTO rapport.clients (
|
|
72
|
-
client_id,
|
|
73
|
-
client_name,
|
|
74
|
-
client_type,
|
|
75
|
-
client_status,
|
|
76
|
-
subscription_tier,
|
|
77
|
-
subscription_status
|
|
78
|
-
)
|
|
79
|
-
VALUES ($1, $2, 'PERSONAL', 'Active', 'free', 'active')
|
|
80
|
-
ON CONFLICT (client_id) DO NOTHING
|
|
81
|
-
RETURNING client_id
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
const clientName = firstName && lastName
|
|
85
|
-
? `${firstName} ${lastName}'s Workspace`
|
|
86
|
-
: `${email.split('@')[0]}'s Workspace`;
|
|
87
|
-
|
|
88
|
-
await executeQuery(clientQuery, [personalClientId, clientName]);
|
|
89
|
-
|
|
90
|
-
console.log('Personal client created:', personalClientId);
|
|
91
|
-
|
|
92
|
-
// 3. Create personal company
|
|
93
|
-
const companyId = `${personalClientId}_main`;
|
|
94
|
-
const companyQuery = `
|
|
95
|
-
INSERT INTO rapport.companies (
|
|
96
|
-
company_id,
|
|
97
|
-
client_id,
|
|
98
|
-
company_name,
|
|
99
|
-
company_status
|
|
100
|
-
)
|
|
101
|
-
VALUES ($1, $2, $3, 'Active')
|
|
102
|
-
ON CONFLICT (company_id) DO NOTHING
|
|
103
|
-
RETURNING company_id
|
|
104
|
-
`;
|
|
105
|
-
|
|
106
|
-
await executeQuery(companyQuery, [
|
|
107
|
-
companyId,
|
|
108
|
-
personalClientId,
|
|
109
|
-
'Personal Projects'
|
|
110
|
-
]);
|
|
111
|
-
|
|
112
|
-
console.log('Personal company created:', companyId);
|
|
113
|
-
|
|
114
|
-
// 4. Create admin entitlement for personal workspace
|
|
115
|
-
const entitlementQuery = `
|
|
116
|
-
INSERT INTO rapport.user_entitlements (
|
|
117
|
-
email_address,
|
|
118
|
-
client_id,
|
|
119
|
-
company_id,
|
|
120
|
-
admin,
|
|
121
|
-
member
|
|
122
|
-
)
|
|
123
|
-
VALUES ($1, $2, $3, true, true)
|
|
124
|
-
ON CONFLICT (email_address, company_id) DO NOTHING
|
|
125
|
-
`;
|
|
126
|
-
|
|
127
|
-
await executeQuery(entitlementQuery, [email, personalClientId, companyId]);
|
|
128
|
-
|
|
129
|
-
console.log('Entitlement created for:', email);
|
|
130
|
-
|
|
131
|
-
// 5. Check for and accept pending enterprise invitations
|
|
132
|
-
const pendingInvites = await executeQuery(`
|
|
133
|
-
SELECT invitation_id, client_id, company_id, role
|
|
134
|
-
FROM rapport.enterprise_invitations
|
|
135
|
-
WHERE email = $1 AND status = 'pending'
|
|
136
|
-
`, [email.toLowerCase()]);
|
|
137
|
-
|
|
138
|
-
if (pendingInvites.rows.length > 0) {
|
|
139
|
-
console.log(`Found ${pendingInvites.rows.length} pending enterprise invitation(s)`);
|
|
140
|
-
|
|
141
|
-
for (const invite of pendingInvites.rows) {
|
|
142
|
-
// Create entitlement for the enterprise company
|
|
143
|
-
const isAdmin = invite.role === 'admin';
|
|
144
|
-
await executeQuery(`
|
|
145
|
-
INSERT INTO rapport.user_entitlements (
|
|
146
|
-
email_address,
|
|
147
|
-
client_id,
|
|
148
|
-
company_id,
|
|
149
|
-
admin,
|
|
150
|
-
member
|
|
151
|
-
)
|
|
152
|
-
VALUES ($1, $2, $3, $4, true)
|
|
153
|
-
ON CONFLICT (email_address, company_id) DO NOTHING
|
|
154
|
-
`, [email, invite.client_id, invite.company_id, isAdmin]);
|
|
155
|
-
|
|
156
|
-
// Mark invitation as accepted
|
|
157
|
-
await executeQuery(`
|
|
158
|
-
UPDATE rapport.enterprise_invitations
|
|
159
|
-
SET status = 'accepted', accepted_at = NOW()
|
|
160
|
-
WHERE invitation_id = $1
|
|
161
|
-
`, [invite.invitation_id]);
|
|
162
|
-
|
|
163
|
-
console.log(`Accepted enterprise invitation for company: ${invite.company_id} (role: ${invite.role})`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
await executeQuery('COMMIT');
|
|
168
|
-
|
|
169
|
-
console.log('Post-confirmation complete for:', email);
|
|
170
|
-
|
|
171
|
-
} catch (error) {
|
|
172
|
-
await executeQuery('ROLLBACK');
|
|
173
|
-
throw error;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
} catch (error) {
|
|
177
|
-
console.error('Post-confirmation error:', error);
|
|
178
|
-
// Don't throw - this would prevent user creation in Cognito
|
|
179
|
-
// Log the error and continue
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Must return the event for Cognito to proceed
|
|
183
|
-
return event;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
module.exports = { handler };
|