@equilateral_ai/mindmeld 3.4.0 → 3.5.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/pre-compact.js +269 -21
- package/hooks/session-end.js +112 -3
- package/hooks/session-start.js +139 -34
- package/package.json +1 -1
- package/scripts/auth-login.js +45 -8
- package/src/core/StandardsIngestion.js +3 -1
- package/src/handlers/collaborators/collaboratorList.js +4 -10
- package/src/handlers/correlations/correlationsProjectGet.js +4 -13
- package/src/handlers/github/githubDiscoverPatterns.js +4 -8
- package/src/handlers/github/githubPatternsReview.js +4 -8
- package/src/handlers/helpers/decisionFrames.js +29 -0
- package/src/handlers/helpers/index.js +14 -0
- package/src/handlers/helpers/mindmeldMcpCore.js +1103 -0
- package/src/handlers/helpers/predictiveCache.js +51 -0
- package/src/handlers/helpers/projectAccess.js +88 -0
- package/src/handlers/mcp/mindmeldMcpHandler.js +8 -573
- package/src/handlers/mcp/mindmeldMcpStreamHandler.js +342 -0
- package/src/handlers/standards/discoveriesGet.js +4 -8
- package/src/handlers/standards/projectStandardsGet.js +5 -11
- package/src/handlers/standards/projectStandardsPut.js +19 -14
- package/src/handlers/standards/standardsParseUpload.js +4 -8
- package/src/handlers/standards/standardsRelevantPost.js +126 -29
- package/src/handlers/users/userGet.js +3 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const { executeQuery } = require('./index');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get standards that are consistently relevant for a project (>80% activation rate over 30 days)
|
|
5
|
+
*/
|
|
6
|
+
async function getPredictedStandards(projectId) {
|
|
7
|
+
const result = await executeQuery(`
|
|
8
|
+
WITH activation_stats AS (
|
|
9
|
+
SELECT
|
|
10
|
+
standard_id,
|
|
11
|
+
COUNT(*) as activation_count,
|
|
12
|
+
COUNT(DISTINCT DATE(activated_at)) as active_days
|
|
13
|
+
FROM rapport.standards_activation_log
|
|
14
|
+
WHERE project_id = $1
|
|
15
|
+
AND activated_at > NOW() - INTERVAL '30 days'
|
|
16
|
+
GROUP BY standard_id
|
|
17
|
+
),
|
|
18
|
+
total_sessions AS (
|
|
19
|
+
SELECT COUNT(DISTINCT DATE(activated_at)) as total_days
|
|
20
|
+
FROM rapport.standards_activation_log
|
|
21
|
+
WHERE project_id = $1
|
|
22
|
+
AND activated_at > NOW() - INTERVAL '30 days'
|
|
23
|
+
)
|
|
24
|
+
SELECT a.standard_id,
|
|
25
|
+
a.activation_count,
|
|
26
|
+
a.active_days,
|
|
27
|
+
t.total_days,
|
|
28
|
+
CASE WHEN t.total_days > 0
|
|
29
|
+
THEN ROUND(a.active_days::numeric / t.total_days * 100, 1)
|
|
30
|
+
ELSE 0 END as activation_rate
|
|
31
|
+
FROM activation_stats a, total_sessions t
|
|
32
|
+
WHERE t.total_days >= 5
|
|
33
|
+
AND a.active_days::numeric / GREATEST(t.total_days, 1) > 0.8
|
|
34
|
+
ORDER BY activation_rate DESC
|
|
35
|
+
`, [projectId]);
|
|
36
|
+
return result.rows;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Log which standards were activated for a project
|
|
41
|
+
*/
|
|
42
|
+
async function logStandardsActivation(projectId, standardIds) {
|
|
43
|
+
if (!standardIds || standardIds.length === 0) return;
|
|
44
|
+
const values = standardIds.map((id, i) => `($1, $${i + 2})`).join(', ');
|
|
45
|
+
await executeQuery(
|
|
46
|
+
`INSERT INTO rapport.standards_activation_log (project_id, standard_id) VALUES ${values}`,
|
|
47
|
+
[projectId, ...standardIds]
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = { getPredictedStandards, logStandardsActivation };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Access Verification
|
|
3
|
+
*
|
|
4
|
+
* Centralizes the "can this user access this project?" check.
|
|
5
|
+
* Grants access if the user is either:
|
|
6
|
+
* 1. A direct project collaborator (rapport.project_collaborators)
|
|
7
|
+
* 2. A member of the company that owns the project (rapport.user_entitlements)
|
|
8
|
+
*
|
|
9
|
+
* Returns the project row (project_id, project_name, company_id) on success,
|
|
10
|
+
* or null if the user has no access.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { executeQuery } = require('./dbOperations');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Verify a user has access to a project via collaborator role or company membership.
|
|
17
|
+
* @param {string} projectId - Project ID to check
|
|
18
|
+
* @param {string} email - User's email address
|
|
19
|
+
* @returns {Promise<{project_id: string, project_name: string, company_id: string, access_type: string}|null>}
|
|
20
|
+
* Project row with access_type ('collaborator' or 'company_member'), or null if no access.
|
|
21
|
+
*/
|
|
22
|
+
async function verifyProjectAccess(projectId, email) {
|
|
23
|
+
const result = await executeQuery(`
|
|
24
|
+
SELECT
|
|
25
|
+
p.project_id,
|
|
26
|
+
p.project_name,
|
|
27
|
+
p.company_id,
|
|
28
|
+
CASE
|
|
29
|
+
WHEN pc.email_address IS NOT NULL THEN 'collaborator'
|
|
30
|
+
WHEN ue.email_address IS NOT NULL THEN 'company_member'
|
|
31
|
+
END as access_type
|
|
32
|
+
FROM rapport.projects p
|
|
33
|
+
LEFT JOIN rapport.project_collaborators pc
|
|
34
|
+
ON p.project_id = pc.project_id
|
|
35
|
+
AND pc.email_address = $2
|
|
36
|
+
LEFT JOIN rapport.user_entitlements ue
|
|
37
|
+
ON p.company_id = ue.company_id
|
|
38
|
+
AND ue.email_address = $2
|
|
39
|
+
WHERE p.project_id = $1
|
|
40
|
+
AND (pc.email_address IS NOT NULL OR ue.email_address IS NOT NULL)
|
|
41
|
+
LIMIT 1
|
|
42
|
+
`, [projectId, email]);
|
|
43
|
+
|
|
44
|
+
return result.rows.length > 0 ? result.rows[0] : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Verify a user has a specific collaborator role on a project,
|
|
49
|
+
* OR is a company admin (which grants equivalent access).
|
|
50
|
+
* @param {string} projectId - Project ID to check
|
|
51
|
+
* @param {string} email - User's email address
|
|
52
|
+
* @param {string[]} allowedRoles - Collaborator roles that grant access (e.g. ['owner', 'admin'])
|
|
53
|
+
* @returns {Promise<{project_id: string, project_name: string, company_id: string, role: string|null, company_admin: boolean}|null>}
|
|
54
|
+
*/
|
|
55
|
+
async function verifyProjectRole(projectId, email, allowedRoles = ['owner', 'admin', 'collaborator']) {
|
|
56
|
+
const result = await executeQuery(`
|
|
57
|
+
SELECT
|
|
58
|
+
p.project_id,
|
|
59
|
+
p.project_name,
|
|
60
|
+
p.company_id,
|
|
61
|
+
pc.role,
|
|
62
|
+
COALESCE(ue.admin, false) as company_admin
|
|
63
|
+
FROM rapport.projects p
|
|
64
|
+
LEFT JOIN rapport.project_collaborators pc
|
|
65
|
+
ON p.project_id = pc.project_id
|
|
66
|
+
AND pc.email_address = $2
|
|
67
|
+
LEFT JOIN rapport.user_entitlements ue
|
|
68
|
+
ON p.company_id = ue.company_id
|
|
69
|
+
AND ue.email_address = $2
|
|
70
|
+
WHERE p.project_id = $1
|
|
71
|
+
AND (pc.email_address IS NOT NULL OR ue.email_address IS NOT NULL)
|
|
72
|
+
LIMIT 1
|
|
73
|
+
`, [projectId, email]);
|
|
74
|
+
|
|
75
|
+
if (result.rows.length === 0) return null;
|
|
76
|
+
|
|
77
|
+
const row = result.rows[0];
|
|
78
|
+
const hasRole = row.role && allowedRoles.includes(row.role);
|
|
79
|
+
const isCompanyAdmin = row.company_admin === true;
|
|
80
|
+
|
|
81
|
+
if (hasRole || isCompanyAdmin) {
|
|
82
|
+
return row;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = { verifyProjectAccess, verifyProjectRole };
|