@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.
Files changed (140) hide show
  1. package/hooks/session-end.js +25 -0
  2. package/hooks/session-start.js +363 -83
  3. package/hooks/session-watcher.js +585 -0
  4. package/package.json +19 -13
  5. package/scripts/init-project.js +9 -23
  6. package/src/client/dbShim.js +16 -0
  7. package/src/core/AuthManager.js +3 -2
  8. package/src/handlers/helpers/dbOperations.js +9 -46
  9. package/src/index.js +2 -217
  10. package/src/utils/piiMask.js +16 -0
  11. package/scripts/harvest.js +0 -601
  12. package/scripts/inject.js +0 -409
  13. package/scripts/mcp-bridge.js +0 -220
  14. package/scripts/repo-analyzer.js +0 -870
  15. package/src/collaboration/CollaborationPrompt.js +0 -460
  16. package/src/core/AlertEngine.js +0 -813
  17. package/src/core/AlertNotifier.js +0 -363
  18. package/src/core/CorrelationAnalyzer.js +0 -931
  19. package/src/core/CrossReferenceEngine.js +0 -624
  20. package/src/core/CurationEngine.js +0 -688
  21. package/src/core/DeprecationScheduler.js +0 -183
  22. package/src/core/LoadBearingDetector.js +0 -242
  23. package/src/core/NotificationService.js +0 -1032
  24. package/src/core/RapportOrchestrator.js +0 -632
  25. package/src/core/RelevanceDetector.js +0 -694
  26. package/src/core/StandardLifecycle.js +0 -244
  27. package/src/core/StandardsIngestion.js +0 -991
  28. package/src/core/TeamLoadBearingDetector.js +0 -431
  29. package/src/core/parsers/adrParser.js +0 -479
  30. package/src/core/parsers/cursorRulesParser.js +0 -564
  31. package/src/core/parsers/eslintParser.js +0 -439
  32. package/src/database/dbOperations.js +0 -105
  33. package/src/handlers/activity/activityGetMe.js +0 -98
  34. package/src/handlers/activity/activityGetTeam.js +0 -175
  35. package/src/handlers/admin/adminSetup.js +0 -216
  36. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  37. package/src/handlers/alerts/alertsGet.js +0 -250
  38. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  39. package/src/handlers/analytics/coachingGet.js +0 -361
  40. package/src/handlers/analytics/convergenceGet.js +0 -236
  41. package/src/handlers/analytics/developerScoreGet.js +0 -137
  42. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  43. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  44. package/src/handlers/collaborators/collaboratorList.js +0 -82
  45. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  46. package/src/handlers/collaborators/inviteAccept.js +0 -122
  47. package/src/handlers/company/companyUsersDelete.js +0 -141
  48. package/src/handlers/company/companyUsersGet.js +0 -90
  49. package/src/handlers/company/companyUsersPost.js +0 -267
  50. package/src/handlers/company/companyUsersPut.js +0 -76
  51. package/src/handlers/context/contextGet.js +0 -57
  52. package/src/handlers/context/invariantsGet.js +0 -74
  53. package/src/handlers/context/loopsGet.js +0 -82
  54. package/src/handlers/context/notesCreate.js +0 -74
  55. package/src/handlers/context/purposeGet.js +0 -78
  56. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  57. package/src/handlers/correlations/correlationsGet.js +0 -93
  58. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  59. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  60. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  61. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  62. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  63. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  64. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  65. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  66. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  67. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  68. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  69. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  70. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  71. package/src/handlers/github/githubConnectionStatus.js +0 -49
  72. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  73. package/src/handlers/github/githubOAuthCallback.js +0 -178
  74. package/src/handlers/github/githubOAuthStart.js +0 -59
  75. package/src/handlers/github/githubPatternsReview.js +0 -76
  76. package/src/handlers/github/githubReposList.js +0 -105
  77. package/src/handlers/health/healthGet.js +0 -55
  78. package/src/handlers/helpers/auditLogger.js +0 -201
  79. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  80. package/src/handlers/helpers/decisionFrames.js +0 -29
  81. package/src/handlers/helpers/errorHandler.js +0 -49
  82. package/src/handlers/helpers/index.js +0 -138
  83. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  84. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  85. package/src/handlers/helpers/predictiveCache.js +0 -51
  86. package/src/handlers/helpers/projectAccess.js +0 -88
  87. package/src/handlers/helpers/responseUtil.js +0 -55
  88. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  89. package/src/handlers/mcp/mcpHandler.js +0 -569
  90. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  91. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  92. package/src/handlers/notifications/getPreferences.js +0 -84
  93. package/src/handlers/notifications/sendNotification.js +0 -170
  94. package/src/handlers/notifications/updatePreferences.js +0 -316
  95. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  96. package/src/handlers/patterns/patternUsagePost.js +0 -182
  97. package/src/handlers/patterns/patternViolationPost.js +0 -185
  98. package/src/handlers/projects/projectCreate.js +0 -248
  99. package/src/handlers/projects/projectDelete.js +0 -82
  100. package/src/handlers/projects/projectGet.js +0 -95
  101. package/src/handlers/projects/projectUpdate.js +0 -117
  102. package/src/handlers/reports/aiLeverage.js +0 -210
  103. package/src/handlers/reports/engineeringInvestment.js +0 -132
  104. package/src/handlers/reports/riskForecast.js +0 -206
  105. package/src/handlers/reports/standardsRoi.js +0 -254
  106. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  107. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  108. package/src/handlers/scheduled/generateAlerts.js +0 -135
  109. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  110. package/src/handlers/scheduled/refreshActivity.js +0 -21
  111. package/src/handlers/scheduled/scanCompliance.js +0 -334
  112. package/src/handlers/sessions/sessionEndPost.js +0 -180
  113. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  114. package/src/handlers/standards/catalogGet.js +0 -185
  115. package/src/handlers/standards/catalogSync.js +0 -120
  116. package/src/handlers/standards/discoveriesGet.js +0 -89
  117. package/src/handlers/standards/projectStandardsGet.js +0 -129
  118. package/src/handlers/standards/projectStandardsPut.js +0 -151
  119. package/src/handlers/standards/standardsAuditGet.js +0 -65
  120. package/src/handlers/standards/standardsParseUpload.js +0 -149
  121. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  122. package/src/handlers/standards/standardsTransition.js +0 -161
  123. package/src/handlers/stripe/addonManagePost.js +0 -240
  124. package/src/handlers/stripe/billingPortalPost.js +0 -93
  125. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  126. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  127. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  128. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  129. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  130. package/src/handlers/stripe/webhookPost.js +0 -482
  131. package/src/handlers/user/apiTokenCreate.js +0 -71
  132. package/src/handlers/user/apiTokenList.js +0 -64
  133. package/src/handlers/user/userSplashAck.js +0 -91
  134. package/src/handlers/user/userSplashGet.js +0 -211
  135. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  136. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  137. package/src/handlers/users/userEntitlementsGet.js +0 -89
  138. package/src/handlers/users/userGet.js +0 -118
  139. package/src/handlers/users/userProfilePut.js +0 -77
  140. package/src/handlers/webhooks/githubWebhook.js +0 -215
@@ -1,267 +0,0 @@
1
- /**
2
- * Company Users Invite Handler
3
- * Invites a user to a company by creating an entitlement and sending an invite email
4
- * Supports two billing modes: self_pays (invitee pays) or admin_pays (license on admin's subscription)
5
- *
6
- * POST /api/company/users
7
- * Body: { company_id, email, role, billing }
8
- * Auth: Cognito JWT required
9
- */
10
-
11
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, getTierConfig } = require('./helpers');
12
- const { SESClient, SendEmailCommand } = require('@aws-sdk/client-ses');
13
- const Stripe = require('stripe');
14
-
15
- const ses = new SESClient({ region: process.env.AWS_REGION || 'us-east-2' });
16
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
17
-
18
- /**
19
- * Invite user to company
20
- * Requires admin access to the company
21
- */
22
- async function inviteCompanyUser({ body: requestBody = {}, requestContext }) {
23
- try {
24
- const Request_ID = requestContext.requestId;
25
- const callerEmail = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
26
- const { company_id, email, role, billing = 'self_pays' } = requestBody;
27
-
28
- if (!callerEmail) {
29
- return createErrorResponse(401, 'Authentication required');
30
- }
31
-
32
- if (!company_id || !email) {
33
- return createErrorResponse(400, 'company_id and email are required');
34
- }
35
-
36
- if (!['admin_pays', 'self_pays'].includes(billing)) {
37
- return createErrorResponse(400, 'billing must be admin_pays or self_pays');
38
- }
39
-
40
- // Verify caller is admin of this company
41
- const adminQuery = `
42
- SELECT ue.admin, ue.client_id, u.first_name, u.last_name
43
- FROM rapport.user_entitlements ue
44
- LEFT JOIN rapport.users u ON u.email_address = ue.email_address
45
- WHERE ue.email_address = $1 AND ue.company_id = $2
46
- `;
47
- const adminCheck = await executeQuery(adminQuery, [callerEmail, company_id]);
48
-
49
- if (adminCheck.rowCount === 0 || !adminCheck.rows[0].admin) {
50
- return createErrorResponse(403, 'Admin access required to invite users');
51
- }
52
-
53
- const clientId = adminCheck.rows[0].client_id;
54
- const inviterName = [adminCheck.rows[0].first_name, adminCheck.rows[0].last_name].filter(Boolean).join(' ') || callerEmail;
55
-
56
- // Get client details for seat limits and Stripe info
57
- const clientQuery = `
58
- SELECT subscription_tier, seat_count, client_name, stripe_subscription_id, license_count
59
- FROM rapport.clients WHERE client_id = $1
60
- `;
61
- const clientResult = await executeQuery(clientQuery, [clientId]);
62
- const clientRecord = clientResult.rows[0];
63
- const tierConfig = getTierConfig(clientRecord?.subscription_tier || 'free');
64
- const maxCollaborators = tierConfig?.maxCollaborators;
65
- const teamName = clientRecord?.client_name || 'their team';
66
- const inviterTier = clientRecord?.subscription_tier || 'team';
67
-
68
- // Check seat limits before allowing invite
69
- if (maxCollaborators !== null) {
70
- const countQuery = `
71
- SELECT COUNT(*) as current_count
72
- FROM rapport.user_entitlements WHERE company_id = $1
73
- `;
74
- const countResult = await executeQuery(countQuery, [company_id]);
75
- const currentCount = parseInt(countResult.rows[0].current_count) || 0;
76
-
77
- if (currentCount >= maxCollaborators) {
78
- return createErrorResponse(403, `Seat limit reached (${currentCount}/${maxCollaborators}). Upgrade your plan to add more team members.`);
79
- }
80
- }
81
-
82
- // For admin_pays, verify admin has an active Stripe subscription
83
- if (billing === 'admin_pays' && !clientRecord?.stripe_subscription_id) {
84
- return createErrorResponse(400, 'You need an active subscription to add licensed users. Subscribe first, then invite with "Add to my subscription".');
85
- }
86
-
87
- // Ensure invited user exists in users table (create pending record if not)
88
- await executeQuery(`
89
- INSERT INTO rapport.users (email_address, user_status, active, create_date)
90
- VALUES ($1, 'Pending', true, NOW())
91
- ON CONFLICT (email_address) DO NOTHING
92
- `, [email]);
93
-
94
- // Create entitlement for invited user
95
- const isAdmin = role === 'admin';
96
- const billingType = billing === 'admin_pays' ? 'admin_paid' : 'self_paid';
97
- const insertQuery = `
98
- INSERT INTO rapport.user_entitlements (
99
- email_address, client_id, company_id, admin, member, billing_type
100
- ) VALUES ($1, $2, $3, $4, true, $5)
101
- ON CONFLICT (email_address, company_id) DO UPDATE SET
102
- admin = EXCLUDED.admin,
103
- member = true,
104
- billing_type = EXCLUDED.billing_type
105
- RETURNING email_address, admin, member, billing_type
106
- `;
107
- const result = await executeQuery(insertQuery, [email, clientId, company_id, isAdmin, billingType]);
108
-
109
- // If admin_pays, update license count and Stripe subscription quantity
110
- let stripeUpdated = false;
111
- if (billing === 'admin_pays') {
112
- // Increment license_count
113
- const updateResult = await executeQuery(`
114
- UPDATE rapport.clients
115
- SET license_count = COALESCE(license_count, 1) + 1, last_updated = CURRENT_TIMESTAMP
116
- WHERE client_id = $1
117
- RETURNING license_count
118
- `, [clientId]);
119
- const newLicenseCount = updateResult.rows[0].license_count;
120
-
121
- // Update Stripe subscription quantity
122
- try {
123
- const subscription = await stripe.subscriptions.retrieve(clientRecord.stripe_subscription_id);
124
- const item = subscription.items.data[0];
125
- if (item) {
126
- await stripe.subscriptions.update(clientRecord.stripe_subscription_id, {
127
- items: [{ id: item.id, quantity: newLicenseCount }],
128
- proration_behavior: 'none'
129
- });
130
- stripeUpdated = true;
131
- console.log(`[License] Updated Stripe quantity to ${newLicenseCount} for ${clientId}`);
132
- }
133
- } catch (stripeError) {
134
- console.error('[License] Stripe update failed:', stripeError.message);
135
- // Revert license_count since Stripe failed
136
- await executeQuery(`
137
- UPDATE rapport.clients
138
- SET license_count = COALESCE(license_count, 2) - 1, last_updated = CURRENT_TIMESTAMP
139
- WHERE client_id = $1
140
- `, [clientId]);
141
- return createErrorResponse(500, 'Failed to update subscription. Please try again or contact support.');
142
- }
143
- }
144
-
145
- // Send invite email
146
- const appUrl = process.env.APP_URL || 'https://app.mindmeld.dev';
147
- // Admin-paid users don't need to go through checkout, so no ?tier= param
148
- const signupUrl = billing === 'admin_pays'
149
- ? `${appUrl}/signup`
150
- : `${appUrl}/signup?tier=${inviterTier}`;
151
- let emailSent = false;
152
-
153
- // Customize email message based on billing type
154
- const billingNote = billing === 'admin_pays'
155
- ? 'Your subscription is covered — just sign up and start using MindMeld.'
156
- : 'MindMeld brings intelligent standards and patterns directly into your AI coding sessions — helping your team write better code, faster.';
157
-
158
- const emailParams = {
159
- Source: process.env.EMAIL_FROM || 'noreply@mindmeld.dev',
160
- Destination: {
161
- ToAddresses: [email]
162
- },
163
- Message: {
164
- Subject: {
165
- Data: `${inviterName} invited you to join ${teamName} on MindMeld`,
166
- Charset: 'UTF-8'
167
- },
168
- Body: {
169
- Html: {
170
- Data: `
171
- <!DOCTYPE html>
172
- <html>
173
- <head>
174
- <meta charset="utf-8">
175
- <style>
176
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; }
177
- .container { max-width: 600px; margin: 0 auto; padding: 20px; }
178
- .header { text-align: center; margin-bottom: 30px; }
179
- .logo { font-size: 24px; font-weight: bold; color: #2563eb; }
180
- .content { background: #f8fafc; border-radius: 8px; padding: 30px; margin-bottom: 20px; }
181
- .button { display: inline-block; background: #2563eb; color: white; padding: 12px 24px; border-radius: 6px; text-decoration: none; font-weight: 500; }
182
- .footer { text-align: center; color: #64748b; font-size: 14px; }
183
- .role-badge { display: inline-block; background: #e0e7ff; color: #3730a3; padding: 4px 12px; border-radius: 20px; font-size: 14px; }
184
- </style>
185
- </head>
186
- <body>
187
- <div class="container">
188
- <div class="header">
189
- <div class="logo">MindMeld</div>
190
- </div>
191
- <div class="content">
192
- <p>Hi there,</p>
193
- <p><strong>${inviterName}</strong> has invited you to join <strong>${teamName}</strong> on MindMeld.</p>
194
- <p>Your role: <span class="role-badge">${isAdmin ? 'Admin' : 'Member'}</span></p>
195
- <p>${billingNote}</p>
196
- <p style="margin-top: 30px;">
197
- <a href="${signupUrl}" class="button">Get Started</a>
198
- </p>
199
- <p style="margin-top: 20px; font-size: 14px; color: #64748b;">
200
- Already have an account? <a href="${appUrl}" style="color: #2563eb;">Sign in</a> — your team access will be ready.
201
- </p>
202
- </div>
203
- <div class="footer">
204
- <p>MindMeld - Intelligent standards for AI coding</p>
205
- <p>Powered by Equilateral AI</p>
206
- </div>
207
- </div>
208
- </body>
209
- </html>
210
- `,
211
- Charset: 'UTF-8'
212
- },
213
- Text: {
214
- Data: `${inviterName} has invited you to join ${teamName} on MindMeld.
215
-
216
- Your role: ${isAdmin ? 'Admin' : 'Member'}
217
-
218
- ${billingNote}
219
-
220
- Get started: ${signupUrl}
221
-
222
- Already have an account? Sign in at ${appUrl} — your team access will be ready.
223
-
224
- ---
225
- MindMeld - Intelligent standards for AI coding
226
- Powered by Equilateral AI
227
- `,
228
- Charset: 'UTF-8'
229
- }
230
- }
231
- }
232
- };
233
-
234
- try {
235
- await ses.send(new SendEmailCommand(emailParams));
236
- emailSent = true;
237
- } catch (sesError) {
238
- console.error('SES Error sending invite:', sesError);
239
- }
240
-
241
- const responseRecords = result.rows.map(r => ({
242
- ...r,
243
- email_sent: emailSent,
244
- stripe_updated: stripeUpdated
245
- }));
246
-
247
- const message = billing === 'admin_pays'
248
- ? `${email} added to your subscription (license ${stripeUpdated ? 'updated' : 'pending'})`
249
- : emailSent ? `Invitation sent to ${email}` : `User ${email} added to team (email delivery failed — share the link manually)`;
250
-
251
- return createSuccessResponse(
252
- { Records: responseRecords },
253
- message,
254
- {
255
- Total_Records: result.rowCount,
256
- Request_ID,
257
- Timestamp: new Date().toISOString()
258
- }
259
- );
260
-
261
- } catch (error) {
262
- console.error('Handler Error:', error);
263
- return handleError(error);
264
- }
265
- }
266
-
267
- exports.handler = wrapHandler(inviteCompanyUser);
@@ -1,76 +0,0 @@
1
- /**
2
- * Company Users Update Handler
3
- * Updates a user's role within a company
4
- *
5
- * PUT /api/company/users
6
- * Body: { company_id, email, role }
7
- * Auth: Cognito JWT required
8
- */
9
-
10
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
11
-
12
- /**
13
- * Update user role in company
14
- * Requires admin access to the company
15
- */
16
- async function updateCompanyUser({ body: requestBody = {}, requestContext }) {
17
- try {
18
- const Request_ID = requestContext.requestId;
19
- const callerEmail = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
20
- const { company_id, email, role } = requestBody;
21
-
22
- if (!callerEmail) {
23
- return createErrorResponse(401, 'Authentication required');
24
- }
25
-
26
- if (!company_id || !email || !role) {
27
- return createErrorResponse(400, 'company_id, email, and role are required');
28
- }
29
-
30
- // Verify caller is admin of this company
31
- const adminQuery = `
32
- SELECT admin FROM rapport.user_entitlements
33
- WHERE email_address = $1 AND company_id = $2
34
- `;
35
- const adminCheck = await executeQuery(adminQuery, [callerEmail, company_id]);
36
-
37
- if (adminCheck.rowCount === 0 || !adminCheck.rows[0].admin) {
38
- return createErrorResponse(403, 'Admin access required to update user roles');
39
- }
40
-
41
- // Prevent self-demotion from admin
42
- if (email === callerEmail && role !== 'admin') {
43
- return createErrorResponse(400, 'Cannot remove your own admin role');
44
- }
45
-
46
- // Update the entitlement
47
- const isAdmin = role === 'admin';
48
- const updateQuery = `
49
- UPDATE rapport.user_entitlements
50
- SET admin = $1
51
- WHERE email_address = $2 AND company_id = $3
52
- RETURNING email_address, admin, member
53
- `;
54
- const result = await executeQuery(updateQuery, [isAdmin, email, company_id]);
55
-
56
- if (result.rowCount === 0) {
57
- return createErrorResponse(404, `User ${email} not found in this company`);
58
- }
59
-
60
- return createSuccessResponse(
61
- { Records: result.rows },
62
- `User ${email} role updated to ${role}`,
63
- {
64
- Total_Records: result.rowCount,
65
- Request_ID,
66
- Timestamp: new Date().toISOString()
67
- }
68
- );
69
-
70
- } catch (error) {
71
- console.error('Handler Error:', error);
72
- return handleError(error);
73
- }
74
- }
75
-
76
- exports.handler = wrapHandler(updateCompanyUser);
@@ -1,57 +0,0 @@
1
- /**
2
- * Context Get Handler
3
- * Retrieves full user context for a scope (invariants, purpose, notes, loops)
4
- * Used by mobile/iOS apps for session injection
5
- *
6
- * GET /api/context?scope=jarvis
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, checkSuperAdmin } = require('./helpers');
10
-
11
- /**
12
- * Get user context for mobile injection
13
- */
14
- async function getContext({ queryStringParameters: queryParams = {}, requestContext }) {
15
- try {
16
- const Request_ID = requestContext.requestId;
17
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
18
-
19
- if (!email) {
20
- return createErrorResponse(401, 'Unauthorized');
21
- }
22
-
23
- // Gate to super admins only (internal/beta endpoint)
24
- await checkSuperAdmin.requireSuperAdmin(email);
25
-
26
- const scope = queryParams.scope || 'jarvis';
27
-
28
- // Use the database function for efficient retrieval
29
- const query = `SELECT rapport.get_user_context($1, $2) as context`;
30
- const result = await executeQuery(query, [email, scope]);
31
-
32
- const context = result.rows[0]?.context || {
33
- invariants: { agent_level: [], relationship_level: [] },
34
- purpose: null,
35
- recent_notes: [],
36
- active_loops: []
37
- };
38
-
39
- return createSuccessResponse(
40
- {
41
- scope,
42
- ...context
43
- },
44
- 'Context retrieved successfully',
45
- {
46
- Request_ID,
47
- Timestamp: new Date().toISOString()
48
- }
49
- );
50
-
51
- } catch (error) {
52
- console.error('Handler Error:', error);
53
- return handleError(error);
54
- }
55
- }
56
-
57
- exports.handler = wrapHandler(getContext);
@@ -1,74 +0,0 @@
1
- /**
2
- * Invariants Get Handler
3
- * Retrieves user invariants for a scope
4
- *
5
- * GET /api/context/invariants?scope=jarvis
6
- */
7
-
8
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, checkSuperAdmin } = require('./helpers');
9
-
10
- /**
11
- * Get user invariants
12
- */
13
- async function getInvariants({ 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 || 'global';
26
-
27
- // Get agent-level invariants (global only)
28
- const agentQuery = `
29
- SELECT invariant_text as text, maturity, tier
30
- FROM rapport.user_invariants
31
- WHERE email_address = $1
32
- AND scope = 'global'
33
- AND level = 'agent'
34
- AND archived_at IS NULL
35
- ORDER BY
36
- CASE tier WHEN 'critical' THEN 1 WHEN 'important' THEN 2 ELSE 3 END,
37
- created_at
38
- `;
39
- const agentResult = await executeQuery(agentQuery, [email]);
40
-
41
- // Get relationship-level invariants (scope-specific)
42
- const relationshipQuery = `
43
- SELECT invariant_text as text, maturity, tier
44
- FROM rapport.user_invariants
45
- WHERE email_address = $1
46
- AND scope = $2
47
- AND level = 'relationship'
48
- AND archived_at IS NULL
49
- ORDER BY
50
- CASE tier WHEN 'critical' THEN 1 WHEN 'important' THEN 2 ELSE 3 END,
51
- created_at
52
- `;
53
- const relationshipResult = await executeQuery(relationshipQuery, [email, scope]);
54
-
55
- return createSuccessResponse(
56
- {
57
- scope,
58
- agent_level: agentResult.rows,
59
- relationship_level: relationshipResult.rows
60
- },
61
- `${agentResult.rowCount} agent + ${relationshipResult.rowCount} relationship invariants`,
62
- {
63
- Request_ID,
64
- Timestamp: new Date().toISOString()
65
- }
66
- );
67
-
68
- } catch (error) {
69
- console.error('Handler Error:', error);
70
- return handleError(error);
71
- }
72
- }
73
-
74
- exports.handler = wrapHandler(getInvariants);
@@ -1,82 +0,0 @@
1
- /**
2
- * Loops Get Handler
3
- * Retrieves active loops for a user
4
- *
5
- * GET /api/context/loops
6
- */
7
-
8
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, checkSuperAdmin } = require('./helpers');
9
-
10
- /**
11
- * Get active loops
12
- */
13
- async function getLoops({ 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 includeCompleted = queryParams.include_completed === 'true';
26
-
27
- let query = `
28
- SELECT
29
- loop_id,
30
- project_scope,
31
- task_description,
32
- completion_promise,
33
- max_iterations,
34
- current_iteration,
35
- status,
36
- promise_found,
37
- started_at,
38
- updated_at,
39
- completed_at
40
- FROM rapport.active_loops
41
- WHERE email_address = $1
42
- `;
43
-
44
- if (!includeCompleted) {
45
- query += ` AND status = 'active'`;
46
- }
47
-
48
- query += ` ORDER BY started_at DESC LIMIT 20`;
49
-
50
- const result = await executeQuery(query, [email]);
51
-
52
- return createSuccessResponse(
53
- {
54
- loops: result.rows.map(row => ({
55
- id: row.loop_id,
56
- scope: row.project_scope,
57
- task: row.task_description,
58
- promise: row.completion_promise,
59
- iteration: row.current_iteration,
60
- max_iterations: row.max_iterations,
61
- status: row.status,
62
- promise_found: row.promise_found,
63
- started_at: row.started_at,
64
- updated_at: row.updated_at,
65
- completed_at: row.completed_at
66
- })),
67
- count: result.rowCount
68
- },
69
- `${result.rowCount} loops`,
70
- {
71
- Request_ID,
72
- Timestamp: new Date().toISOString()
73
- }
74
- );
75
-
76
- } catch (error) {
77
- console.error('Handler Error:', error);
78
- return handleError(error);
79
- }
80
- }
81
-
82
- exports.handler = wrapHandler(getLoops);
@@ -1,74 +0,0 @@
1
- /**
2
- * Notes Create Handler
3
- * Creates a new context note from mobile/iOS
4
- *
5
- * POST /api/context/notes
6
- * Body: { content: "...", scope: "jarvis", tags: ["mobile"] }
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError, checkSuperAdmin } = require('./helpers');
10
-
11
- /**
12
- * Create context note
13
- */
14
- async function createNote({ body, requestContext }) {
15
- try {
16
- const Request_ID = requestContext.requestId;
17
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
18
-
19
- if (!email) {
20
- return createErrorResponse(401, 'Unauthorized');
21
- }
22
-
23
- // Gate to super admins only (internal/beta endpoint)
24
- await checkSuperAdmin.requireSuperAdmin(email);
25
-
26
- const data = typeof body === 'string' ? JSON.parse(body) : body;
27
-
28
- if (!data.content || data.content.trim() === '') {
29
- return createErrorResponse(400, 'Content is required');
30
- }
31
-
32
- const scope = data.scope || 'global';
33
- const tags = data.tags || [];
34
- const source = data.source || 'mobile';
35
- const metadata = data.metadata || {};
36
-
37
- const query = `
38
- INSERT INTO rapport.context_notes
39
- (email_address, scope, content, tags, source, metadata)
40
- VALUES ($1, $2, $3, $4, $5, $6)
41
- RETURNING note_id, created_at
42
- `;
43
-
44
- const result = await executeQuery(query, [
45
- email,
46
- scope,
47
- data.content.trim(),
48
- JSON.stringify(tags),
49
- source,
50
- JSON.stringify(metadata)
51
- ]);
52
-
53
- const note = result.rows[0];
54
-
55
- return createSuccessResponse(
56
- {
57
- note_id: note.note_id,
58
- scope,
59
- created_at: note.created_at
60
- },
61
- `Note created: ${note.note_id}`,
62
- {
63
- Request_ID,
64
- Timestamp: new Date().toISOString()
65
- }
66
- );
67
-
68
- } catch (error) {
69
- console.error('Handler Error:', error);
70
- return handleError(error);
71
- }
72
- }
73
-
74
- exports.handler = wrapHandler(createNote);