@equilateral_ai/mindmeld 3.5.2 → 4.0.1

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