@equilateral_ai/mindmeld 3.5.3 → 4.0.1

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