@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.
- package/hooks/session-start.js +312 -85
- package/package.json +20 -14
- package/scripts/init-project.js +9 -23
- package/src/client/dbShim.js +16 -0
- package/src/core/AuthManager.js +3 -2
- package/src/handlers/helpers/dbOperations.js +9 -46
- package/src/index.js +2 -217
- package/src/utils/piiMask.js +16 -0
- package/scripts/harvest.js +0 -601
- package/scripts/inject.js +0 -409
- package/scripts/mcp-bridge.js +0 -220
- package/scripts/repo-analyzer.js +0 -870
- package/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,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Standards Handler
|
|
3
|
-
* Records which standards were shown during a Claude Code session
|
|
4
|
-
*
|
|
5
|
-
* POST /api/sessions/standards
|
|
6
|
-
* Body: { session_id, standards[], project_id?, user_id? }
|
|
7
|
-
*
|
|
8
|
-
* Called by: session-start.js hook (recordStandardsShown method)
|
|
9
|
-
* Fire-and-forget - should not block session start
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Record standards shown during session
|
|
16
|
-
* Creates session record if needed, then records standards
|
|
17
|
-
*/
|
|
18
|
-
async function recordSessionStandards({ body: requestBody = {}, requestContext }) {
|
|
19
|
-
try {
|
|
20
|
-
const Request_ID = requestContext?.requestId || 'unknown';
|
|
21
|
-
|
|
22
|
-
const {
|
|
23
|
-
session_id,
|
|
24
|
-
standards = [],
|
|
25
|
-
project_id,
|
|
26
|
-
user_id
|
|
27
|
-
} = requestBody;
|
|
28
|
-
|
|
29
|
-
// Validate required fields
|
|
30
|
-
if (!session_id) {
|
|
31
|
-
return createErrorResponse(400, 'session_id is required');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!standards || standards.length === 0) {
|
|
35
|
-
// Not an error - just nothing to record
|
|
36
|
-
return createSuccessResponse(
|
|
37
|
-
{ Records: [], recorded: 0 },
|
|
38
|
-
'No standards to record',
|
|
39
|
-
{ Request_ID, Timestamp: new Date().toISOString() }
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Try to ensure session exists (upsert with minimal data)
|
|
44
|
-
// If project doesn't exist, auto-create it to prevent silent session loss
|
|
45
|
-
if (project_id && user_id) {
|
|
46
|
-
const sessionUpsertQuery = `
|
|
47
|
-
INSERT INTO rapport.sessions (
|
|
48
|
-
session_id,
|
|
49
|
-
project_id,
|
|
50
|
-
email_address,
|
|
51
|
-
started_at,
|
|
52
|
-
session_data
|
|
53
|
-
) VALUES (
|
|
54
|
-
$1, $2, $3, NOW(), '{}'::jsonb
|
|
55
|
-
)
|
|
56
|
-
ON CONFLICT (session_id) DO NOTHING
|
|
57
|
-
`;
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
await executeQuery(sessionUpsertQuery, [session_id, project_id, user_id]);
|
|
61
|
-
} catch (sessionError) {
|
|
62
|
-
// FK constraint on project_id — auto-create the project and retry
|
|
63
|
-
if (sessionError.code === '23503' && sessionError.constraint && sessionError.constraint.includes('project_id')) {
|
|
64
|
-
console.log(`[sessionStandardsPost] Project ${project_id} not found, auto-creating`);
|
|
65
|
-
try {
|
|
66
|
-
// Look up user's company_id
|
|
67
|
-
const entResult = await executeQuery(
|
|
68
|
-
`SELECT company_id FROM rapport.user_entitlements WHERE email_address = $1 LIMIT 1`,
|
|
69
|
-
[user_id]
|
|
70
|
-
);
|
|
71
|
-
if (entResult.rowCount > 0) {
|
|
72
|
-
const company_id = entResult.rows[0].company_id;
|
|
73
|
-
// Derive a readable project name from the project_id
|
|
74
|
-
// e.g. prj_pareidolia_main_1770727596802 → pareidolia main
|
|
75
|
-
const projectName = project_id
|
|
76
|
-
.replace(/^prj_/, '')
|
|
77
|
-
.replace(/_\d+$/, '')
|
|
78
|
-
.replace(/_/g, ' ');
|
|
79
|
-
|
|
80
|
-
await executeQuery(`
|
|
81
|
-
INSERT INTO rapport.projects (project_id, company_id, project_name, private)
|
|
82
|
-
VALUES ($1, $2, $3, false)
|
|
83
|
-
ON CONFLICT (project_id) DO NOTHING
|
|
84
|
-
`, [project_id, company_id, projectName]);
|
|
85
|
-
|
|
86
|
-
// Retry session upsert
|
|
87
|
-
await executeQuery(sessionUpsertQuery, [session_id, project_id, user_id]);
|
|
88
|
-
console.log(`[sessionStandardsPost] Auto-created project ${project_id} under ${company_id}`);
|
|
89
|
-
} else {
|
|
90
|
-
console.error(`[sessionStandardsPost] No entitlement found for ${user_id}, cannot auto-create project`);
|
|
91
|
-
}
|
|
92
|
-
} catch (autoCreateError) {
|
|
93
|
-
console.error('[sessionStandardsPost] Auto-create project failed:', autoCreateError.message);
|
|
94
|
-
}
|
|
95
|
-
} else {
|
|
96
|
-
console.error('[sessionStandardsPost] Session upsert failed:', sessionError.message);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Record each standard shown
|
|
102
|
-
const recordedStandards = [];
|
|
103
|
-
let errors = 0;
|
|
104
|
-
|
|
105
|
-
for (const standard of standards) {
|
|
106
|
-
const standardId = standard.pattern_id || standard.element;
|
|
107
|
-
const standardName = standard.title || standard.element || standardId;
|
|
108
|
-
const relevanceScore = standard.relevance_score || standard.score || 0;
|
|
109
|
-
|
|
110
|
-
if (!standardId) {
|
|
111
|
-
errors++;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const insertQuery = `
|
|
116
|
-
INSERT INTO rapport.session_standards (
|
|
117
|
-
session_id,
|
|
118
|
-
standard_id,
|
|
119
|
-
standard_name,
|
|
120
|
-
relevance_score,
|
|
121
|
-
created_at
|
|
122
|
-
) VALUES (
|
|
123
|
-
$1, $2, $3, $4, NOW()
|
|
124
|
-
)
|
|
125
|
-
ON CONFLICT (session_id, standard_id) DO UPDATE SET
|
|
126
|
-
relevance_score = EXCLUDED.relevance_score,
|
|
127
|
-
created_at = NOW()
|
|
128
|
-
RETURNING id
|
|
129
|
-
`;
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
const result = await executeQuery(insertQuery, [
|
|
133
|
-
session_id,
|
|
134
|
-
standardId,
|
|
135
|
-
standardName,
|
|
136
|
-
relevanceScore
|
|
137
|
-
]);
|
|
138
|
-
|
|
139
|
-
recordedStandards.push({
|
|
140
|
-
id: result.rows[0]?.id,
|
|
141
|
-
standard_id: standardId,
|
|
142
|
-
relevance_score: relevanceScore
|
|
143
|
-
});
|
|
144
|
-
} catch (insertError) {
|
|
145
|
-
// Standard might not exist or FK constraint failed
|
|
146
|
-
console.error(`[sessionStandardsPost] Failed to record standard ${standardId}:`, insertError.message);
|
|
147
|
-
errors++;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return createSuccessResponse(
|
|
152
|
-
{
|
|
153
|
-
Records: recordedStandards,
|
|
154
|
-
recorded: recordedStandards.length,
|
|
155
|
-
errors: errors
|
|
156
|
-
},
|
|
157
|
-
`Recorded ${recordedStandards.length} standard(s)`,
|
|
158
|
-
{
|
|
159
|
-
Total_Records: recordedStandards.length,
|
|
160
|
-
Request_ID,
|
|
161
|
-
Timestamp: new Date().toISOString()
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
} catch (error) {
|
|
166
|
-
console.error('Handler Error:', error);
|
|
167
|
-
return handleError(error);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
exports.handler = wrapHandler(recordSessionStandards);
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standards Catalog Get Handler
|
|
3
|
-
* Returns the standards catalog manifest based on subscription tier
|
|
4
|
-
*
|
|
5
|
-
* GET /api/standards/catalog
|
|
6
|
-
* Auth: Cognito JWT required
|
|
7
|
-
* Query params:
|
|
8
|
-
* - catalog_id: Override catalog selection
|
|
9
|
-
* - tech_stack: Comma-separated list of detected technologies for recommendations
|
|
10
|
-
*
|
|
11
|
-
* Enterprise tier: Full proprietary standards (equilateral-v1)
|
|
12
|
-
* Other tiers: Open standards only (equilateral-open-v1)
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
16
|
-
|
|
17
|
-
// Enterprise tiers that get full proprietary standards
|
|
18
|
-
const ENTERPRISE_TIERS = ['enterprise', 'enterprise_private', 'enterprise_team'];
|
|
19
|
-
|
|
20
|
-
// Tech stack to category recommendations mapping
|
|
21
|
-
const TECH_TO_CATEGORIES = {
|
|
22
|
-
// Languages/Frameworks
|
|
23
|
-
'react': ['frontend-development'],
|
|
24
|
-
'vue': ['frontend-development'],
|
|
25
|
-
'angular': ['frontend-development'],
|
|
26
|
-
'typescript': ['frontend-development'],
|
|
27
|
-
'node.js': ['serverless-saas-aws'],
|
|
28
|
-
'nodejs': ['serverless-saas-aws'],
|
|
29
|
-
'express': ['serverless-saas-aws'],
|
|
30
|
-
|
|
31
|
-
// Infrastructure
|
|
32
|
-
'aws sam': ['serverless-saas-aws'],
|
|
33
|
-
'aws lambda': ['serverless-saas-aws'],
|
|
34
|
-
'lambda': ['serverless-saas-aws'],
|
|
35
|
-
'serverless': ['serverless-saas-aws'],
|
|
36
|
-
'cloudformation': ['serverless-saas-aws'],
|
|
37
|
-
'api gateway': ['serverless-saas-aws'],
|
|
38
|
-
|
|
39
|
-
// Databases
|
|
40
|
-
'postgresql': ['database-patterns', 'memory-systems'],
|
|
41
|
-
'postgres': ['database-patterns', 'memory-systems'],
|
|
42
|
-
'dynamodb': ['serverless-saas-aws'],
|
|
43
|
-
|
|
44
|
-
// Testing
|
|
45
|
-
'jest': ['frontend-development'],
|
|
46
|
-
|
|
47
|
-
// Multi-agent
|
|
48
|
-
'claude': ['multi-agent-orchestration'],
|
|
49
|
-
'openai': ['multi-agent-orchestration'],
|
|
50
|
-
'langchain': ['multi-agent-orchestration'],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get recommended categories based on detected tech stack
|
|
55
|
-
* @param {string} techStackParam - Comma-separated tech stack string
|
|
56
|
-
* @returns {string[]} - Unique list of recommended category keys
|
|
57
|
-
*/
|
|
58
|
-
function getRecommendations(techStackParam) {
|
|
59
|
-
if (!techStackParam) return [];
|
|
60
|
-
|
|
61
|
-
const technologies = techStackParam.split(',').map(t => t.trim().toLowerCase());
|
|
62
|
-
const recommendations = new Set();
|
|
63
|
-
|
|
64
|
-
for (const tech of technologies) {
|
|
65
|
-
const categories = TECH_TO_CATEGORIES[tech];
|
|
66
|
-
if (categories) {
|
|
67
|
-
categories.forEach(cat => recommendations.add(cat));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return Array.from(recommendations);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async function getCatalog({ requestContext, queryStringParameters }) {
|
|
75
|
-
try {
|
|
76
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
77
|
-
|
|
78
|
-
if (!email) {
|
|
79
|
-
return createErrorResponse(401, 'Authentication required');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Get user's subscription tier
|
|
83
|
-
const userResult = await executeQuery(`
|
|
84
|
-
SELECT c.subscription_tier
|
|
85
|
-
FROM rapport.users u
|
|
86
|
-
LEFT JOIN rapport.clients c ON u.client_id = c.client_id
|
|
87
|
-
WHERE u.email_address = $1 AND u.active = true
|
|
88
|
-
`, [email]);
|
|
89
|
-
|
|
90
|
-
const subscriptionTier = userResult.rows[0]?.subscription_tier || 'free';
|
|
91
|
-
const isEnterprise = ENTERPRISE_TIERS.includes(subscriptionTier);
|
|
92
|
-
|
|
93
|
-
// Get tech stack recommendations if provided
|
|
94
|
-
const techStack = queryStringParameters?.tech_stack;
|
|
95
|
-
const recommendations = getRecommendations(techStack);
|
|
96
|
-
|
|
97
|
-
// Determine which catalog to return based on tier
|
|
98
|
-
// Enterprise gets full catalog, others get open standards
|
|
99
|
-
const catalogId = queryStringParameters?.catalog_id ||
|
|
100
|
-
(isEnterprise ? 'equilateral-v1' : 'equilateral-open-v1');
|
|
101
|
-
|
|
102
|
-
const result = await executeQuery(`
|
|
103
|
-
SELECT
|
|
104
|
-
catalog_id,
|
|
105
|
-
version,
|
|
106
|
-
source_url,
|
|
107
|
-
updated_at,
|
|
108
|
-
total_standards,
|
|
109
|
-
total_layers,
|
|
110
|
-
categories,
|
|
111
|
-
layers,
|
|
112
|
-
critical_alerts
|
|
113
|
-
FROM rapport.standards_catalog
|
|
114
|
-
WHERE catalog_id = $1
|
|
115
|
-
`, [catalogId]);
|
|
116
|
-
|
|
117
|
-
if (result.rowCount === 0) {
|
|
118
|
-
// Fall back to open standards if requested catalog not found
|
|
119
|
-
const fallbackResult = await executeQuery(`
|
|
120
|
-
SELECT
|
|
121
|
-
catalog_id,
|
|
122
|
-
version,
|
|
123
|
-
source_url,
|
|
124
|
-
updated_at,
|
|
125
|
-
total_standards,
|
|
126
|
-
total_layers,
|
|
127
|
-
categories,
|
|
128
|
-
layers,
|
|
129
|
-
critical_alerts
|
|
130
|
-
FROM rapport.standards_catalog
|
|
131
|
-
WHERE catalog_id = 'equilateral-open-v1'
|
|
132
|
-
`);
|
|
133
|
-
|
|
134
|
-
if (fallbackResult.rowCount === 0) {
|
|
135
|
-
return createErrorResponse(404, 'Standards catalog not found', {
|
|
136
|
-
catalog_id: catalogId,
|
|
137
|
-
hint: 'Run migration or sync catalog first'
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const catalog = fallbackResult.rows[0];
|
|
142
|
-
return createSuccessResponse({
|
|
143
|
-
catalog_id: catalog.catalog_id,
|
|
144
|
-
version: catalog.version,
|
|
145
|
-
source_url: catalog.source_url,
|
|
146
|
-
updated_at: catalog.updated_at,
|
|
147
|
-
subscription_tier: subscriptionTier,
|
|
148
|
-
is_enterprise: false,
|
|
149
|
-
recommendations,
|
|
150
|
-
summary: {
|
|
151
|
-
total_standards: catalog.total_standards,
|
|
152
|
-
total_layers: catalog.total_layers
|
|
153
|
-
},
|
|
154
|
-
categories: catalog.categories,
|
|
155
|
-
layers: catalog.layers,
|
|
156
|
-
critical_alerts: catalog.critical_alerts
|
|
157
|
-
}, 'Open standards catalog retrieved');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const catalog = result.rows[0];
|
|
161
|
-
|
|
162
|
-
return createSuccessResponse({
|
|
163
|
-
catalog_id: catalog.catalog_id,
|
|
164
|
-
version: catalog.version,
|
|
165
|
-
source_url: catalog.source_url,
|
|
166
|
-
updated_at: catalog.updated_at,
|
|
167
|
-
subscription_tier: subscriptionTier,
|
|
168
|
-
is_enterprise: isEnterprise,
|
|
169
|
-
recommendations,
|
|
170
|
-
summary: {
|
|
171
|
-
total_standards: catalog.total_standards,
|
|
172
|
-
total_layers: catalog.total_layers
|
|
173
|
-
},
|
|
174
|
-
categories: catalog.categories,
|
|
175
|
-
layers: catalog.layers,
|
|
176
|
-
critical_alerts: catalog.critical_alerts
|
|
177
|
-
}, isEnterprise ? 'Full standards catalog retrieved' : 'Open standards catalog retrieved');
|
|
178
|
-
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.error('Catalog Get Error:', error);
|
|
181
|
-
return createErrorResponse(500, 'Failed to retrieve standards catalog');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
exports.handler = wrapHandler(getCatalog);
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standards Catalog Sync Handler
|
|
3
|
-
* Imports/updates the standards catalog from manifest.json
|
|
4
|
-
*
|
|
5
|
-
* POST /api/standards/catalog/sync
|
|
6
|
-
* Body: { manifest } - The manifest.json content
|
|
7
|
-
* Auth: Cognito JWT required (admin only)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
|
|
11
|
-
|
|
12
|
-
async function syncCatalog({ body, requestContext }) {
|
|
13
|
-
try {
|
|
14
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
15
|
-
|
|
16
|
-
if (!email) {
|
|
17
|
-
return createErrorResponse(401, 'Authentication required');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { manifest, catalog_id = 'equilateral-v1', source_url } = body || {};
|
|
21
|
-
|
|
22
|
-
if (!manifest) {
|
|
23
|
-
return createErrorResponse(400, 'manifest is required');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Validate manifest structure
|
|
27
|
-
if (!manifest.version || !manifest.categories || !manifest.layers) {
|
|
28
|
-
return createErrorResponse(400, 'Invalid manifest: missing version, categories, or layers');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Extract metadata
|
|
32
|
-
const totalStandards = manifest.metadata?.totalStandards || 0;
|
|
33
|
-
const totalLayers = manifest.layers?.length || 0;
|
|
34
|
-
|
|
35
|
-
// Build categories object with descriptions
|
|
36
|
-
const categories = {};
|
|
37
|
-
if (manifest.categories) {
|
|
38
|
-
for (const [key, description] of Object.entries(manifest.categories)) {
|
|
39
|
-
categories[key] = {
|
|
40
|
-
name: key.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
|
|
41
|
-
description: description,
|
|
42
|
-
// Count files in this category from layers
|
|
43
|
-
standards_count: 0
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Count standards per category from layers
|
|
49
|
-
if (manifest.layers) {
|
|
50
|
-
for (const layer of manifest.layers) {
|
|
51
|
-
if (layer.files) {
|
|
52
|
-
for (const file of layer.files) {
|
|
53
|
-
const category = file.split('/')[0];
|
|
54
|
-
if (categories[category]) {
|
|
55
|
-
categories[category].standards_count++;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Upsert catalog
|
|
63
|
-
const result = await executeQuery(`
|
|
64
|
-
INSERT INTO rapport.standards_catalog (
|
|
65
|
-
catalog_id,
|
|
66
|
-
version,
|
|
67
|
-
source_url,
|
|
68
|
-
manifest,
|
|
69
|
-
total_standards,
|
|
70
|
-
total_layers,
|
|
71
|
-
categories,
|
|
72
|
-
layers,
|
|
73
|
-
critical_alerts,
|
|
74
|
-
updated_at
|
|
75
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW())
|
|
76
|
-
ON CONFLICT (catalog_id) DO UPDATE SET
|
|
77
|
-
version = EXCLUDED.version,
|
|
78
|
-
source_url = EXCLUDED.source_url,
|
|
79
|
-
manifest = EXCLUDED.manifest,
|
|
80
|
-
total_standards = EXCLUDED.total_standards,
|
|
81
|
-
total_layers = EXCLUDED.total_layers,
|
|
82
|
-
categories = EXCLUDED.categories,
|
|
83
|
-
layers = EXCLUDED.layers,
|
|
84
|
-
critical_alerts = EXCLUDED.critical_alerts,
|
|
85
|
-
updated_at = NOW()
|
|
86
|
-
RETURNING catalog_id, version, updated_at
|
|
87
|
-
`, [
|
|
88
|
-
catalog_id,
|
|
89
|
-
manifest.version,
|
|
90
|
-
source_url || manifest.metadata?.repository || null,
|
|
91
|
-
JSON.stringify(manifest),
|
|
92
|
-
totalStandards,
|
|
93
|
-
totalLayers,
|
|
94
|
-
JSON.stringify(categories),
|
|
95
|
-
JSON.stringify(manifest.layers),
|
|
96
|
-
JSON.stringify(manifest.criticalAlerts || [])
|
|
97
|
-
]);
|
|
98
|
-
|
|
99
|
-
const synced = result.rows[0];
|
|
100
|
-
|
|
101
|
-
return createSuccessResponse({
|
|
102
|
-
catalog_id: synced.catalog_id,
|
|
103
|
-
version: synced.version,
|
|
104
|
-
updated_at: synced.updated_at,
|
|
105
|
-
summary: {
|
|
106
|
-
total_standards: totalStandards,
|
|
107
|
-
total_layers: totalLayers,
|
|
108
|
-
total_categories: Object.keys(categories).length,
|
|
109
|
-
critical_alerts: (manifest.criticalAlerts || []).length
|
|
110
|
-
},
|
|
111
|
-
categories: Object.keys(categories)
|
|
112
|
-
}, 'Standards catalog synced successfully');
|
|
113
|
-
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('Catalog Sync Error:', error);
|
|
116
|
-
return createErrorResponse(500, 'Failed to sync standards catalog');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
exports.handler = wrapHandler(syncCatalog);
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discoveries Get Handler
|
|
3
|
-
* Returns discovery review queue for a project
|
|
4
|
-
*
|
|
5
|
-
* GET /api/standards/discoveries?project_id=xxx&status=proposed
|
|
6
|
-
* Auth: Cognito JWT required
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, verifyProjectAccess } = require('./helpers');
|
|
10
|
-
|
|
11
|
-
async function getDiscoveries({ queryStringParameters, requestContext }) {
|
|
12
|
-
try {
|
|
13
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
14
|
-
|
|
15
|
-
if (!email) {
|
|
16
|
-
return createErrorResponse(401, 'Authentication required');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const projectId = (queryStringParameters || {}).project_id;
|
|
20
|
-
const status = (queryStringParameters || {}).status;
|
|
21
|
-
|
|
22
|
-
if (!projectId) {
|
|
23
|
-
return createErrorResponse(400, 'project_id is required');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Verify user has access to project (collaborator or company member)
|
|
27
|
-
const projectAccess = await verifyProjectAccess(projectId, email);
|
|
28
|
-
if (!projectAccess) {
|
|
29
|
-
return createErrorResponse(403, 'Access denied to project');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Build query with optional status filter
|
|
33
|
-
let query = `
|
|
34
|
-
SELECT
|
|
35
|
-
discovery_id,
|
|
36
|
-
project_id,
|
|
37
|
-
pattern_name,
|
|
38
|
-
pattern_description,
|
|
39
|
-
confidence,
|
|
40
|
-
discovery_type,
|
|
41
|
-
status,
|
|
42
|
-
evidence,
|
|
43
|
-
reason,
|
|
44
|
-
reason_code,
|
|
45
|
-
created_at,
|
|
46
|
-
updated_at
|
|
47
|
-
FROM rapport.onboarding_discoveries
|
|
48
|
-
WHERE project_id = $1
|
|
49
|
-
`;
|
|
50
|
-
const params = [projectId];
|
|
51
|
-
|
|
52
|
-
if (status) {
|
|
53
|
-
query += ` AND status = $2`;
|
|
54
|
-
params.push(status);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
query += ` ORDER BY confidence DESC, created_at DESC`;
|
|
58
|
-
|
|
59
|
-
const result = await executeQuery(query, params);
|
|
60
|
-
|
|
61
|
-
// Map DB columns to frontend Discovery interface
|
|
62
|
-
const records = result.rows.map(row => ({
|
|
63
|
-
id: row.discovery_id,
|
|
64
|
-
project_id: row.project_id,
|
|
65
|
-
name: row.pattern_name,
|
|
66
|
-
description: row.pattern_description || '',
|
|
67
|
-
confidence: parseFloat(row.confidence) || 0,
|
|
68
|
-
source: 'github',
|
|
69
|
-
category: row.discovery_type || 'Architecture',
|
|
70
|
-
status: row.status || 'proposed',
|
|
71
|
-
rule_text: null,
|
|
72
|
-
action_type: null,
|
|
73
|
-
evidence: row.evidence || null,
|
|
74
|
-
created_at: row.created_at,
|
|
75
|
-
updated_at: row.updated_at
|
|
76
|
-
}));
|
|
77
|
-
|
|
78
|
-
return createSuccessResponse({
|
|
79
|
-
records,
|
|
80
|
-
total: result.rowCount
|
|
81
|
-
}, `Found ${result.rowCount} discoveries`);
|
|
82
|
-
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.error('Discoveries Get Error:', error);
|
|
85
|
-
return createErrorResponse(500, 'Failed to load discoveries');
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
exports.handler = wrapHandler(getDiscoveries);
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project Standards Get Handler
|
|
3
|
-
* Returns standards preferences for a project
|
|
4
|
-
*
|
|
5
|
-
* GET /api/projects/standards?project_id=xxx
|
|
6
|
-
* Auth: Cognito JWT required
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, verifyProjectAccess } = require('./helpers');
|
|
10
|
-
|
|
11
|
-
async function getProjectStandards({ queryStringParameters, pathParameters, requestContext }) {
|
|
12
|
-
try {
|
|
13
|
-
const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
|
|
14
|
-
|
|
15
|
-
if (!email) {
|
|
16
|
-
return createErrorResponse(401, 'Authentication required');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const projectId = pathParameters?.projectId || (queryStringParameters || {}).project_id;
|
|
20
|
-
|
|
21
|
-
if (!projectId) {
|
|
22
|
-
return createErrorResponse(400, 'projectId is required');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Verify user has access to project (collaborator or company member)
|
|
26
|
-
const projectAccess = await verifyProjectAccess(projectId, email);
|
|
27
|
-
if (!projectAccess) {
|
|
28
|
-
return createErrorResponse(403, 'Access denied to project');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const projectName = projectAccess.project_name;
|
|
32
|
-
|
|
33
|
-
// Get project standards preferences
|
|
34
|
-
const prefsResult = await executeQuery(`
|
|
35
|
-
SELECT
|
|
36
|
-
ps.catalog_id,
|
|
37
|
-
ps.enabled_categories,
|
|
38
|
-
ps.standard_overrides,
|
|
39
|
-
ps.critical_overrides,
|
|
40
|
-
ps.modified_by,
|
|
41
|
-
ps.modified_at,
|
|
42
|
-
sc.version as catalog_version,
|
|
43
|
-
sc.categories as available_categories,
|
|
44
|
-
sc.layers as available_layers,
|
|
45
|
-
sc.critical_alerts,
|
|
46
|
-
sc.total_standards
|
|
47
|
-
FROM rapport.project_standards ps
|
|
48
|
-
JOIN rapport.standards_catalog sc ON ps.catalog_id = sc.catalog_id
|
|
49
|
-
WHERE ps.project_id = $1
|
|
50
|
-
`, [projectId]);
|
|
51
|
-
|
|
52
|
-
// If no preferences exist, return defaults with catalog info
|
|
53
|
-
if (prefsResult.rowCount === 0) {
|
|
54
|
-
const catalogResult = await executeQuery(`
|
|
55
|
-
SELECT
|
|
56
|
-
catalog_id,
|
|
57
|
-
version,
|
|
58
|
-
categories,
|
|
59
|
-
layers,
|
|
60
|
-
critical_alerts,
|
|
61
|
-
total_standards
|
|
62
|
-
FROM rapport.standards_catalog
|
|
63
|
-
WHERE catalog_id = 'equilateral-v1'
|
|
64
|
-
`);
|
|
65
|
-
|
|
66
|
-
if (catalogResult.rowCount === 0) {
|
|
67
|
-
return createErrorResponse(404, 'Standards catalog not found');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const catalog = catalogResult.rows[0];
|
|
71
|
-
|
|
72
|
-
// Default: all categories enabled
|
|
73
|
-
const defaultCategories = {};
|
|
74
|
-
if (catalog.categories) {
|
|
75
|
-
for (const key of Object.keys(catalog.categories)) {
|
|
76
|
-
defaultCategories[key] = true;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return createSuccessResponse({
|
|
81
|
-
project_id: projectId,
|
|
82
|
-
project_name: projectName,
|
|
83
|
-
catalog_id: catalog.catalog_id,
|
|
84
|
-
catalog_version: catalog.version,
|
|
85
|
-
has_custom_preferences: false,
|
|
86
|
-
preferences: {
|
|
87
|
-
enabled_categories: defaultCategories,
|
|
88
|
-
standard_overrides: {},
|
|
89
|
-
critical_overrides: {}
|
|
90
|
-
},
|
|
91
|
-
catalog: {
|
|
92
|
-
categories: catalog.categories,
|
|
93
|
-
layers: catalog.layers,
|
|
94
|
-
critical_alerts: catalog.critical_alerts,
|
|
95
|
-
total_standards: catalog.total_standards
|
|
96
|
-
}
|
|
97
|
-
}, 'Default standards preferences');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const prefs = prefsResult.rows[0];
|
|
101
|
-
|
|
102
|
-
return createSuccessResponse({
|
|
103
|
-
project_id: projectId,
|
|
104
|
-
project_name: projectName,
|
|
105
|
-
catalog_id: prefs.catalog_id,
|
|
106
|
-
catalog_version: prefs.catalog_version,
|
|
107
|
-
has_custom_preferences: true,
|
|
108
|
-
preferences: {
|
|
109
|
-
enabled_categories: prefs.enabled_categories || {},
|
|
110
|
-
standard_overrides: prefs.standard_overrides || {},
|
|
111
|
-
critical_overrides: prefs.critical_overrides || {}
|
|
112
|
-
},
|
|
113
|
-
catalog: {
|
|
114
|
-
categories: prefs.available_categories,
|
|
115
|
-
layers: prefs.available_layers,
|
|
116
|
-
critical_alerts: prefs.critical_alerts,
|
|
117
|
-
total_standards: prefs.total_standards
|
|
118
|
-
},
|
|
119
|
-
modified_by: prefs.modified_by,
|
|
120
|
-
modified_at: prefs.modified_at
|
|
121
|
-
}, 'Project standards preferences retrieved');
|
|
122
|
-
|
|
123
|
-
} catch (error) {
|
|
124
|
-
console.error('Project Standards Get Error:', error);
|
|
125
|
-
return createErrorResponse(500, 'Failed to retrieve project standards');
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
exports.handler = wrapHandler(getProjectStandards);
|