@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
package/scripts/inject.js
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* MindMeld CLI - Inject relevant standards into AI coding tool config
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* mindmeld inject # stdout (raw markdown)
|
|
7
|
-
* mindmeld inject --format cursorrules
|
|
8
|
-
* mindmeld inject --format windsurfrules
|
|
9
|
-
* mindmeld inject --format aider
|
|
10
|
-
* mindmeld inject --format claude # Claude Code hook format
|
|
11
|
-
*
|
|
12
|
-
* @equilateral_ai/mindmeld v3.0.0
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const path = require('path');
|
|
16
|
-
const fs = require('fs').promises;
|
|
17
|
-
|
|
18
|
-
const FORMATS = {
|
|
19
|
-
raw: { file: null, description: 'Raw markdown to stdout' },
|
|
20
|
-
cursorrules: { file: '.cursorrules', description: 'Cursor rules file' },
|
|
21
|
-
windsurfrules: { file: '.windsurfrules', description: 'Windsurf rules file' },
|
|
22
|
-
aider: { file: '.aider.conventions.md', description: 'Aider conventions file' },
|
|
23
|
-
claude: { file: null, description: 'Claude Code hook format (stdout)' }
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function showInjectHelp() {
|
|
27
|
-
console.log(`
|
|
28
|
-
MindMeld inject - Generate context-aware standards for any AI coding tool
|
|
29
|
-
|
|
30
|
-
Usage:
|
|
31
|
-
mindmeld inject [options]
|
|
32
|
-
|
|
33
|
-
Options:
|
|
34
|
-
--format <type> Output format (default: raw)
|
|
35
|
-
--path <dir> Project path (default: current directory)
|
|
36
|
-
--help, -h Show this help
|
|
37
|
-
|
|
38
|
-
Formats:
|
|
39
|
-
raw Plain markdown to stdout (pipe anywhere)
|
|
40
|
-
cursorrules Write .cursorrules file
|
|
41
|
-
windsurfrules Write .windsurfrules file
|
|
42
|
-
aider Write .aider.conventions.md file
|
|
43
|
-
claude Claude Code hook format (stdout)
|
|
44
|
-
|
|
45
|
-
Examples:
|
|
46
|
-
mindmeld inject # Print standards to stdout
|
|
47
|
-
mindmeld inject --format cursorrules # Update .cursorrules
|
|
48
|
-
mindmeld inject --format aider # Update aider conventions
|
|
49
|
-
mindmeld inject | ollama run qwen3-coder # Pipe to local model
|
|
50
|
-
mindmeld inject --format raw >> system.txt # Append to system prompt
|
|
51
|
-
`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Detect project context by scanning files in the working directory
|
|
56
|
-
*/
|
|
57
|
-
async function detectProjectContext(projectPath) {
|
|
58
|
-
const context = {
|
|
59
|
-
projectName: path.basename(projectPath),
|
|
60
|
-
languages: [],
|
|
61
|
-
frameworks: [],
|
|
62
|
-
files: []
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Check for common project indicators
|
|
66
|
-
const checks = [
|
|
67
|
-
{ file: 'package.json', language: 'javascript', frameworks: ['node'] },
|
|
68
|
-
{ file: 'tsconfig.json', language: 'typescript', frameworks: ['node'] },
|
|
69
|
-
{ file: 'template.yaml', language: 'yaml', frameworks: ['aws-sam'] },
|
|
70
|
-
{ file: 'serverless.yml', language: 'yaml', frameworks: ['serverless'] },
|
|
71
|
-
{ file: 'Dockerfile', language: 'docker', frameworks: ['docker'] },
|
|
72
|
-
{ file: 'requirements.txt', language: 'python', frameworks: [] },
|
|
73
|
-
{ file: 'go.mod', language: 'go', frameworks: [] },
|
|
74
|
-
{ file: 'Cargo.toml', language: 'rust', frameworks: [] },
|
|
75
|
-
{ file: '.terraform', language: 'hcl', frameworks: ['terraform'] }
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
for (const check of checks) {
|
|
79
|
-
try {
|
|
80
|
-
await fs.access(path.join(projectPath, check.file));
|
|
81
|
-
if (!context.languages.includes(check.language)) {
|
|
82
|
-
context.languages.push(check.language);
|
|
83
|
-
}
|
|
84
|
-
context.frameworks.push(...check.frameworks);
|
|
85
|
-
context.files.push(check.file);
|
|
86
|
-
} catch (error) {
|
|
87
|
-
// Expected: file doesn't exist
|
|
88
|
-
if (error.code !== 'ENOENT' && error.code !== 'EACCES') {
|
|
89
|
-
console.error(`Unexpected error checking ${check.file}:`, error.message);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Check for specific patterns in package.json
|
|
95
|
-
try {
|
|
96
|
-
const pkg = JSON.parse(await fs.readFile(path.join(projectPath, 'package.json'), 'utf-8'));
|
|
97
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
98
|
-
if (deps['react'] || deps['next']) context.frameworks.push('react');
|
|
99
|
-
if (deps['express'] || deps['fastify']) context.frameworks.push('api');
|
|
100
|
-
if (deps['@aws-sdk']) context.frameworks.push('aws');
|
|
101
|
-
if (deps['pg'] || deps['mysql2'] || deps['mongoose']) context.frameworks.push('database');
|
|
102
|
-
} catch (error) {
|
|
103
|
-
// Expected: no package.json or invalid JSON
|
|
104
|
-
if (error.code !== 'ENOENT' && !(error instanceof SyntaxError)) {
|
|
105
|
-
console.error('Unexpected error reading package.json:', error.message);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return context;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Load and score standards from .equilateral-standards
|
|
114
|
-
*/
|
|
115
|
-
async function getRelevantStandards(projectPath, context) {
|
|
116
|
-
const standardsDir = path.join(projectPath, '.equilateral-standards');
|
|
117
|
-
const standards = [];
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
await fs.access(standardsDir);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
// Expected: standards dir doesn't exist
|
|
123
|
-
if (error.code !== 'ENOENT') {
|
|
124
|
-
console.error('Unexpected error accessing standards:', error.message);
|
|
125
|
-
}
|
|
126
|
-
return [];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Recursively find all .md standard files from community repo
|
|
130
|
-
async function scanDir(dir) {
|
|
131
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
132
|
-
for (const entry of entries) {
|
|
133
|
-
const fullPath = path.join(dir, entry.name);
|
|
134
|
-
if (entry.isDirectory()) {
|
|
135
|
-
await scanDir(fullPath);
|
|
136
|
-
} else if (entry.name.endsWith('.md') && entry.name !== 'README.md') {
|
|
137
|
-
try {
|
|
138
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
139
|
-
const relativePath = path.relative(standardsDir, fullPath);
|
|
140
|
-
const category = path.dirname(relativePath).replace(/\//g, '/');
|
|
141
|
-
standards.push({
|
|
142
|
-
element: entry.name.replace('.md', '').replace(/_/g, ' '),
|
|
143
|
-
category: category === '.' ? 'general' : category,
|
|
144
|
-
content: content,
|
|
145
|
-
path: relativePath,
|
|
146
|
-
score: 0
|
|
147
|
-
});
|
|
148
|
-
} catch (error) {
|
|
149
|
-
// Expected: file not readable
|
|
150
|
-
if (error.code !== 'ENOENT' && error.code !== 'EACCES') {
|
|
151
|
-
console.error(`Unexpected error reading ${fullPath}:`, error.message);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
await scanDir(standardsDir);
|
|
159
|
-
|
|
160
|
-
// Score relevance based on project context
|
|
161
|
-
for (const standard of standards) {
|
|
162
|
-
let score = 0;
|
|
163
|
-
const contentLower = standard.content.toLowerCase();
|
|
164
|
-
const categoryLower = standard.category.toLowerCase();
|
|
165
|
-
|
|
166
|
-
// Language match
|
|
167
|
-
for (const lang of context.languages) {
|
|
168
|
-
if (contentLower.includes(lang) || categoryLower.includes(lang)) {
|
|
169
|
-
score += 3;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Framework match
|
|
174
|
-
for (const fw of context.frameworks) {
|
|
175
|
-
if (contentLower.includes(fw) || categoryLower.includes(fw)) {
|
|
176
|
-
score += 5;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Category relevance boost
|
|
181
|
-
if (categoryLower.includes('serverless') && context.frameworks.includes('aws-sam')) score += 4;
|
|
182
|
-
if (categoryLower.includes('api') && context.frameworks.includes('api')) score += 4;
|
|
183
|
-
if (categoryLower.includes('database') && context.frameworks.includes('database')) score += 4;
|
|
184
|
-
if (categoryLower.includes('react') && context.frameworks.includes('react')) score += 4;
|
|
185
|
-
if (categoryLower.includes('cost') && context.frameworks.includes('aws')) score += 3;
|
|
186
|
-
|
|
187
|
-
// Base score for all standards (everyone gets some relevance)
|
|
188
|
-
score += 1;
|
|
189
|
-
|
|
190
|
-
standard.score = score;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Sort by relevance, return top 10
|
|
194
|
-
standards.sort((a, b) => b.score - a.score);
|
|
195
|
-
return standards.slice(0, 10);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Load team patterns from .mindmeld config
|
|
200
|
-
*/
|
|
201
|
-
async function loadTeamPatterns(projectPath) {
|
|
202
|
-
try {
|
|
203
|
-
const configPath = path.join(projectPath, '.mindmeld', 'config.json');
|
|
204
|
-
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
|
|
205
|
-
return {
|
|
206
|
-
projectName: config.projectName || path.basename(projectPath),
|
|
207
|
-
collaborators: config.collaborators || [],
|
|
208
|
-
team: config.team || false
|
|
209
|
-
};
|
|
210
|
-
} catch (error) {
|
|
211
|
-
// Expected: config doesn't exist or invalid JSON
|
|
212
|
-
if (error.code !== 'ENOENT' && !(error instanceof SyntaxError)) {
|
|
213
|
-
console.error('Unexpected error loading team patterns:', error.message);
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
projectName: path.basename(projectPath),
|
|
217
|
-
collaborators: [],
|
|
218
|
-
team: false
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Format standards as raw markdown
|
|
225
|
-
*/
|
|
226
|
-
function formatRaw(standards, projectInfo, context) {
|
|
227
|
-
const sections = [];
|
|
228
|
-
|
|
229
|
-
sections.push(`# Standards for ${projectInfo.projectName}`);
|
|
230
|
-
sections.push(`<!-- Generated by MindMeld | ${new Date().toISOString()} -->`);
|
|
231
|
-
sections.push(`<!-- Context: ${context.languages.join(', ')} | ${context.frameworks.join(', ')} -->`);
|
|
232
|
-
sections.push('');
|
|
233
|
-
|
|
234
|
-
if (standards.length === 0) {
|
|
235
|
-
sections.push('No standards found. Run `mindmeld init` to set up your project.');
|
|
236
|
-
return sections.join('\n');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
sections.push(`Injecting ${standards.length} relevant standards (of ${standards.length} scored):`);
|
|
240
|
-
sections.push('');
|
|
241
|
-
|
|
242
|
-
for (const standard of standards) {
|
|
243
|
-
sections.push(`## ${standard.element}`);
|
|
244
|
-
sections.push(`**Category**: ${standard.category} | **Relevance**: ${standard.score}`);
|
|
245
|
-
sections.push('');
|
|
246
|
-
// Truncate content to keep injection lean
|
|
247
|
-
const lines = standard.content.split('\n');
|
|
248
|
-
const truncated = lines.slice(0, 30).join('\n');
|
|
249
|
-
sections.push(truncated);
|
|
250
|
-
if (lines.length > 30) {
|
|
251
|
-
sections.push('...');
|
|
252
|
-
}
|
|
253
|
-
sections.push('');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
sections.push('---');
|
|
257
|
-
sections.push('*Generated by MindMeld - mindmeld.dev*');
|
|
258
|
-
|
|
259
|
-
return sections.join('\n');
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Format for .cursorrules / .windsurfrules (compact rules format)
|
|
264
|
-
*/
|
|
265
|
-
function formatRulesFile(standards, projectInfo, context) {
|
|
266
|
-
const sections = [];
|
|
267
|
-
|
|
268
|
-
sections.push(`# Project Standards - ${projectInfo.projectName}`);
|
|
269
|
-
sections.push(`# Auto-generated by MindMeld (mindmeld.dev)`);
|
|
270
|
-
sections.push(`# Context: ${context.frameworks.join(', ') || context.languages.join(', ')}`);
|
|
271
|
-
sections.push(`# Run \`mindmeld inject --format ${context._format}\` to regenerate`);
|
|
272
|
-
sections.push('');
|
|
273
|
-
|
|
274
|
-
for (const standard of standards) {
|
|
275
|
-
sections.push(`## ${standard.element}`);
|
|
276
|
-
// Extract just the key rules, not full prose
|
|
277
|
-
const lines = standard.content.split('\n');
|
|
278
|
-
const ruleLines = lines.filter(l =>
|
|
279
|
-
l.startsWith('- ') || l.startsWith('* ') ||
|
|
280
|
-
l.startsWith(' - ') || l.startsWith('> ') ||
|
|
281
|
-
l.match(/^#{1,4}\s/) || l.match(/^\*\*[^*]+\*\*:/)
|
|
282
|
-
).slice(0, 10);
|
|
283
|
-
|
|
284
|
-
if (ruleLines.length > 0) {
|
|
285
|
-
sections.push(ruleLines.join('\n'));
|
|
286
|
-
} else {
|
|
287
|
-
// Fallback: first meaningful paragraph
|
|
288
|
-
const meaningful = lines.filter(l => l.trim().length > 20 && !l.startsWith('#')).slice(0, 3);
|
|
289
|
-
sections.push(meaningful.join('\n'));
|
|
290
|
-
}
|
|
291
|
-
sections.push('');
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return sections.join('\n');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Format for aider conventions
|
|
299
|
-
*/
|
|
300
|
-
function formatAider(standards, projectInfo, context) {
|
|
301
|
-
const sections = [];
|
|
302
|
-
|
|
303
|
-
sections.push(`# Coding Conventions - ${projectInfo.projectName}`);
|
|
304
|
-
sections.push('');
|
|
305
|
-
sections.push(`> Auto-generated by MindMeld (mindmeld.dev)`);
|
|
306
|
-
sections.push(`> Run \`mindmeld inject --format aider\` to regenerate`);
|
|
307
|
-
sections.push('');
|
|
308
|
-
|
|
309
|
-
for (const standard of standards) {
|
|
310
|
-
sections.push(`## ${standard.element}`);
|
|
311
|
-
sections.push('');
|
|
312
|
-
// Aider conventions prefer concise bullet points
|
|
313
|
-
const lines = standard.content.split('\n');
|
|
314
|
-
const bullets = lines.filter(l =>
|
|
315
|
-
l.startsWith('- ') || l.startsWith('* ') || l.match(/^\*\*[^*]+\*\*:/)
|
|
316
|
-
).slice(0, 8);
|
|
317
|
-
|
|
318
|
-
if (bullets.length > 0) {
|
|
319
|
-
sections.push(bullets.join('\n'));
|
|
320
|
-
} else {
|
|
321
|
-
const meaningful = lines.filter(l => l.trim().length > 10 && !l.startsWith('#')).slice(0, 4);
|
|
322
|
-
sections.push(meaningful.join('\n'));
|
|
323
|
-
}
|
|
324
|
-
sections.push('');
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return sections.join('\n');
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Main inject execution
|
|
332
|
-
*/
|
|
333
|
-
async function inject(options = {}) {
|
|
334
|
-
const format = options.format || 'raw';
|
|
335
|
-
const projectPath = options.path || process.cwd();
|
|
336
|
-
|
|
337
|
-
if (!FORMATS[format]) {
|
|
338
|
-
console.error(`Unknown format: ${format}`);
|
|
339
|
-
console.error(`Available: ${Object.keys(FORMATS).join(', ')}`);
|
|
340
|
-
process.exit(1);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Standalone detection (no database, no prompts, works everywhere)
|
|
344
|
-
let standards = [];
|
|
345
|
-
let projectInfo = {};
|
|
346
|
-
let context = {};
|
|
347
|
-
|
|
348
|
-
context = await detectProjectContext(projectPath);
|
|
349
|
-
standards = await getRelevantStandards(projectPath, context);
|
|
350
|
-
projectInfo = await loadTeamPatterns(projectPath);
|
|
351
|
-
|
|
352
|
-
context._format = format;
|
|
353
|
-
|
|
354
|
-
// 2. Format output
|
|
355
|
-
let output;
|
|
356
|
-
switch (format) {
|
|
357
|
-
case 'cursorrules':
|
|
358
|
-
case 'windsurfrules':
|
|
359
|
-
output = formatRulesFile(standards, projectInfo, context);
|
|
360
|
-
break;
|
|
361
|
-
case 'aider':
|
|
362
|
-
output = formatAider(standards, projectInfo, context);
|
|
363
|
-
break;
|
|
364
|
-
case 'claude':
|
|
365
|
-
// Use the session-start formatter with mapped fields
|
|
366
|
-
try {
|
|
367
|
-
const { formatContextInjection } = require('../hooks/session-start');
|
|
368
|
-
const mappedStandards = standards.map(s => ({
|
|
369
|
-
element: s.element,
|
|
370
|
-
category: s.category,
|
|
371
|
-
rule: s.content.split('\n').find(l => l.trim().length > 10 && !l.startsWith('#')) || s.element
|
|
372
|
-
}));
|
|
373
|
-
output = formatContextInjection({
|
|
374
|
-
project: projectInfo.projectName,
|
|
375
|
-
relevantStandards: mappedStandards,
|
|
376
|
-
teamPatterns: [],
|
|
377
|
-
recentLearning: [],
|
|
378
|
-
collaborators: projectInfo.collaborators || []
|
|
379
|
-
});
|
|
380
|
-
} catch (error) {
|
|
381
|
-
// Expected: module not found in standalone mode
|
|
382
|
-
if (error.code !== 'MODULE_NOT_FOUND') {
|
|
383
|
-
console.error('Unexpected error with claude format:', error.message);
|
|
384
|
-
}
|
|
385
|
-
output = formatRaw(standards, projectInfo, context);
|
|
386
|
-
}
|
|
387
|
-
break;
|
|
388
|
-
case 'raw':
|
|
389
|
-
default:
|
|
390
|
-
output = formatRaw(standards, projectInfo, context);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// 3. Write to file or stdout
|
|
395
|
-
const targetFile = FORMATS[format].file;
|
|
396
|
-
|
|
397
|
-
if (targetFile) {
|
|
398
|
-
const targetPath = path.join(projectPath, targetFile);
|
|
399
|
-
await fs.writeFile(targetPath, output);
|
|
400
|
-
console.error(`[MindMeld] Written ${standards.length} standards to ${targetFile}`);
|
|
401
|
-
console.error(`[MindMeld] Context: ${context.languages ? context.languages.join(', ') : 'unknown'} | ${context.frameworks ? context.frameworks.join(', ') : ''}`);
|
|
402
|
-
console.error(`[MindMeld] Regenerate anytime: mindmeld inject --format ${format}`);
|
|
403
|
-
} else {
|
|
404
|
-
// Output to stdout (for piping)
|
|
405
|
-
console.log(output);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
module.exports = { inject, showInjectHelp, FORMATS };
|
package/scripts/mcp-bridge.js
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MindMeld MCP Bridge - Stdio-to-HTTP proxy for MCP clients
|
|
3
|
-
*
|
|
4
|
-
* Bridges stdio MCP transport to the remote MindMeld MCP server.
|
|
5
|
-
* For clients that don't support URL transport natively
|
|
6
|
-
* (Cline, Cursor, Windsurf, etc.)
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* MINDMELD_TOKEN=mm_live_xxx mindmeld mcp
|
|
10
|
-
* mindmeld mcp --token mm_live_xxx
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const https = require('https');
|
|
14
|
-
const os = require('os');
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
|
|
18
|
-
const MCP_HOST = 'api.mindmeld.dev';
|
|
19
|
-
const MCP_PATH = '/api/mcp/mindmeld';
|
|
20
|
-
const REQUEST_TIMEOUT = 30000;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Resolve API token from env var, CLI arg, or stored file
|
|
24
|
-
*/
|
|
25
|
-
function resolveToken(cliToken) {
|
|
26
|
-
if (process.env.MINDMELD_TOKEN) {
|
|
27
|
-
return process.env.MINDMELD_TOKEN;
|
|
28
|
-
}
|
|
29
|
-
if (cliToken) {
|
|
30
|
-
return cliToken;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const tokenPath = path.join(os.homedir(), '.mindmeld', 'api-token');
|
|
34
|
-
return fs.readFileSync(tokenPath, 'utf-8').trim();
|
|
35
|
-
} catch (err) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Forward a JSON-RPC message to the remote MCP server
|
|
42
|
-
*/
|
|
43
|
-
function forwardToServer(message, token) {
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
const body = JSON.stringify(message);
|
|
46
|
-
const req = https.request({
|
|
47
|
-
method: 'POST',
|
|
48
|
-
hostname: MCP_HOST,
|
|
49
|
-
path: MCP_PATH,
|
|
50
|
-
headers: {
|
|
51
|
-
'Content-Type': 'application/json',
|
|
52
|
-
'Accept': 'application/json',
|
|
53
|
-
'X-MindMeld-Token': token
|
|
54
|
-
},
|
|
55
|
-
timeout: REQUEST_TIMEOUT
|
|
56
|
-
}, (res) => {
|
|
57
|
-
let data = '';
|
|
58
|
-
res.on('data', chunk => data += chunk);
|
|
59
|
-
res.on('end', () => {
|
|
60
|
-
if (res.statusCode === 202 || !data.trim()) {
|
|
61
|
-
resolve(null);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
resolve(JSON.parse(data));
|
|
66
|
-
} catch (e) {
|
|
67
|
-
reject(new Error(`Invalid JSON from server: ${data.substring(0, 200)}`));
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
req.on('timeout', () => {
|
|
73
|
-
req.destroy();
|
|
74
|
-
reject(new Error('Request timed out'));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
req.on('error', (e) => {
|
|
78
|
-
reject(new Error(`Connection failed: ${e.message}`));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
req.write(body);
|
|
82
|
-
req.end();
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Process a single JSON-RPC message from stdin
|
|
88
|
-
*/
|
|
89
|
-
async function processMessage(line, token) {
|
|
90
|
-
let message;
|
|
91
|
-
try {
|
|
92
|
-
message = JSON.parse(line);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
process.stdout.write(JSON.stringify({
|
|
95
|
-
jsonrpc: '2.0',
|
|
96
|
-
error: { code: -32700, message: 'Parse error: invalid JSON' },
|
|
97
|
-
id: null
|
|
98
|
-
}) + '\n');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const isNotification = !('id' in message);
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const response = await forwardToServer(message, token);
|
|
106
|
-
|
|
107
|
-
if (response === null || isNotification) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
process.stdout.write(JSON.stringify(response) + '\n');
|
|
112
|
-
} catch (error) {
|
|
113
|
-
process.stderr.write(`[MindMeld] ${error.message}\n`);
|
|
114
|
-
|
|
115
|
-
if (!isNotification && message.id !== undefined) {
|
|
116
|
-
process.stdout.write(JSON.stringify({
|
|
117
|
-
jsonrpc: '2.0',
|
|
118
|
-
error: { code: -32603, message: error.message },
|
|
119
|
-
id: message.id
|
|
120
|
-
}) + '\n');
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Start the stdio bridge — long-lived, runs until stdin closes
|
|
127
|
-
*/
|
|
128
|
-
function startBridge(token) {
|
|
129
|
-
process.stderr.write(`[MindMeld] MCP bridge started (pid ${process.pid})\n`);
|
|
130
|
-
process.stderr.write(`[MindMeld] Proxying to https://${MCP_HOST}${MCP_PATH}\n`);
|
|
131
|
-
|
|
132
|
-
let buffer = '';
|
|
133
|
-
let pending = 0;
|
|
134
|
-
let stdinClosed = false;
|
|
135
|
-
|
|
136
|
-
function maybeExit() {
|
|
137
|
-
if (stdinClosed && pending === 0) {
|
|
138
|
-
process.stderr.write('[MindMeld] All requests complete, shutting down\n');
|
|
139
|
-
process.exit(0);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function trackMessage(line) {
|
|
144
|
-
pending++;
|
|
145
|
-
processMessage(line, token).finally(() => {
|
|
146
|
-
pending--;
|
|
147
|
-
maybeExit();
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
process.stdin.setEncoding('utf-8');
|
|
152
|
-
|
|
153
|
-
process.stdin.on('data', (chunk) => {
|
|
154
|
-
buffer += chunk;
|
|
155
|
-
const lines = buffer.split('\n');
|
|
156
|
-
buffer = lines.pop();
|
|
157
|
-
|
|
158
|
-
for (const line of lines) {
|
|
159
|
-
const trimmed = line.trim();
|
|
160
|
-
if (!trimmed) continue;
|
|
161
|
-
trackMessage(trimmed);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
process.stdin.on('end', () => {
|
|
166
|
-
process.stderr.write('[MindMeld] stdin closed\n');
|
|
167
|
-
stdinClosed = true;
|
|
168
|
-
maybeExit();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
process.stdin.on('error', (err) => {
|
|
172
|
-
process.stderr.write(`[MindMeld] stdin error: ${err.message}\n`);
|
|
173
|
-
process.exit(1);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function showMcpHelp() {
|
|
178
|
-
console.log(`
|
|
179
|
-
MindMeld MCP Bridge - Stdio-to-HTTP proxy for MCP clients
|
|
180
|
-
|
|
181
|
-
Usage:
|
|
182
|
-
mindmeld mcp [options]
|
|
183
|
-
|
|
184
|
-
Options:
|
|
185
|
-
--token <token> MindMeld API token (or set MINDMELD_TOKEN env var)
|
|
186
|
-
--help, -h Show this help
|
|
187
|
-
|
|
188
|
-
Token Resolution (in priority order):
|
|
189
|
-
1. MINDMELD_TOKEN environment variable
|
|
190
|
-
2. --token CLI argument
|
|
191
|
-
3. ~/.mindmeld/api-token file
|
|
192
|
-
|
|
193
|
-
Create a token at: https://app.mindmeld.dev/api-tokens
|
|
194
|
-
|
|
195
|
-
Client Configuration:
|
|
196
|
-
Cline / Cursor / Windsurf:
|
|
197
|
-
{
|
|
198
|
-
"mcpServers": {
|
|
199
|
-
"mindmeld": {
|
|
200
|
-
"command": "mindmeld",
|
|
201
|
-
"args": ["mcp"],
|
|
202
|
-
"env": { "MINDMELD_TOKEN": "mm_live_xxx" }
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
Claude Code (use URL transport instead — no bridge needed):
|
|
208
|
-
{
|
|
209
|
-
"mcpServers": {
|
|
210
|
-
"mindmeld": {
|
|
211
|
-
"type": "url",
|
|
212
|
-
"url": "https://api.mindmeld.dev/api/mcp/mindmeld",
|
|
213
|
-
"headers": { "X-MindMeld-Token": "mm_live_xxx" }
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
`);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
module.exports = { startBridge, resolveToken, showMcpHelp };
|