@equilateral_ai/mindmeld 3.5.3 → 4.0.1

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