@equilateral_ai/mindmeld 3.0.0

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 (86) hide show
  1. package/README.md +300 -0
  2. package/hooks/README.md +494 -0
  3. package/hooks/pre-compact.js +392 -0
  4. package/hooks/session-start.js +264 -0
  5. package/package.json +90 -0
  6. package/scripts/harvest.js +561 -0
  7. package/scripts/init-project.js +437 -0
  8. package/scripts/inject.js +388 -0
  9. package/src/collaboration/CollaborationPrompt.js +460 -0
  10. package/src/core/AlertEngine.js +813 -0
  11. package/src/core/AlertNotifier.js +363 -0
  12. package/src/core/CorrelationAnalyzer.js +774 -0
  13. package/src/core/CurationEngine.js +688 -0
  14. package/src/core/LLMPatternDetector.js +508 -0
  15. package/src/core/LoadBearingDetector.js +242 -0
  16. package/src/core/NotificationService.js +1032 -0
  17. package/src/core/PatternValidator.js +355 -0
  18. package/src/core/README.md +160 -0
  19. package/src/core/RapportOrchestrator.js +446 -0
  20. package/src/core/RelevanceDetector.js +577 -0
  21. package/src/core/StandardsIngestion.js +575 -0
  22. package/src/core/TeamLoadBearingDetector.js +431 -0
  23. package/src/database/dbOperations.js +105 -0
  24. package/src/handlers/activity/activityGetMe.js +98 -0
  25. package/src/handlers/activity/activityGetTeam.js +130 -0
  26. package/src/handlers/alerts/alertsAcknowledge.js +91 -0
  27. package/src/handlers/alerts/alertsGet.js +250 -0
  28. package/src/handlers/collaborators/collaboratorAdd.js +201 -0
  29. package/src/handlers/collaborators/collaboratorInvite.js +218 -0
  30. package/src/handlers/collaborators/collaboratorList.js +88 -0
  31. package/src/handlers/collaborators/collaboratorRemove.js +127 -0
  32. package/src/handlers/collaborators/inviteAccept.js +122 -0
  33. package/src/handlers/context/contextGet.js +57 -0
  34. package/src/handlers/context/invariantsGet.js +74 -0
  35. package/src/handlers/context/loopsGet.js +82 -0
  36. package/src/handlers/context/notesCreate.js +74 -0
  37. package/src/handlers/context/purposeGet.js +78 -0
  38. package/src/handlers/correlations/correlationsDeveloperGet.js +226 -0
  39. package/src/handlers/correlations/correlationsGet.js +93 -0
  40. package/src/handlers/correlations/correlationsProjectGet.js +161 -0
  41. package/src/handlers/github/githubConnectionStatus.js +49 -0
  42. package/src/handlers/github/githubDiscoverPatterns.js +364 -0
  43. package/src/handlers/github/githubOAuthCallback.js +166 -0
  44. package/src/handlers/github/githubOAuthStart.js +59 -0
  45. package/src/handlers/github/githubPatternsReview.js +109 -0
  46. package/src/handlers/github/githubReposList.js +105 -0
  47. package/src/handlers/helpers/checkSuperAdmin.js +85 -0
  48. package/src/handlers/helpers/dbOperations.js +53 -0
  49. package/src/handlers/helpers/errorHandler.js +49 -0
  50. package/src/handlers/helpers/index.js +106 -0
  51. package/src/handlers/helpers/lambdaWrapper.js +60 -0
  52. package/src/handlers/helpers/responseUtil.js +55 -0
  53. package/src/handlers/helpers/subscriptionTiers.js +1168 -0
  54. package/src/handlers/notifications/getPreferences.js +84 -0
  55. package/src/handlers/notifications/sendNotification.js +170 -0
  56. package/src/handlers/notifications/updatePreferences.js +316 -0
  57. package/src/handlers/patterns/patternUsagePost.js +182 -0
  58. package/src/handlers/patterns/patternViolationPost.js +185 -0
  59. package/src/handlers/projects/projectCreate.js +107 -0
  60. package/src/handlers/projects/projectDelete.js +82 -0
  61. package/src/handlers/projects/projectGet.js +95 -0
  62. package/src/handlers/projects/projectUpdate.js +118 -0
  63. package/src/handlers/reports/aiLeverage.js +206 -0
  64. package/src/handlers/reports/engineeringInvestment.js +132 -0
  65. package/src/handlers/reports/riskForecast.js +186 -0
  66. package/src/handlers/reports/standardsRoi.js +162 -0
  67. package/src/handlers/scheduled/analyzeCorrelations.js +178 -0
  68. package/src/handlers/scheduled/analyzeGitHistory.js +510 -0
  69. package/src/handlers/scheduled/generateAlerts.js +135 -0
  70. package/src/handlers/scheduled/refreshActivity.js +21 -0
  71. package/src/handlers/scheduled/scanCompliance.js +334 -0
  72. package/src/handlers/sessions/sessionEndPost.js +180 -0
  73. package/src/handlers/sessions/sessionStandardsPost.js +135 -0
  74. package/src/handlers/stripe/addonManagePost.js +240 -0
  75. package/src/handlers/stripe/billingPortalPost.js +93 -0
  76. package/src/handlers/stripe/enterpriseCheckoutPost.js +272 -0
  77. package/src/handlers/stripe/seatsUpdatePost.js +185 -0
  78. package/src/handlers/stripe/subscriptionCancelDelete.js +169 -0
  79. package/src/handlers/stripe/subscriptionCreatePost.js +221 -0
  80. package/src/handlers/stripe/subscriptionUpdatePut.js +163 -0
  81. package/src/handlers/stripe/webhookPost.js +454 -0
  82. package/src/handlers/users/cognitoPostConfirmation.js +150 -0
  83. package/src/handlers/users/userEntitlementsGet.js +89 -0
  84. package/src/handlers/users/userGet.js +114 -0
  85. package/src/handlers/webhooks/githubWebhook.js +223 -0
  86. package/src/index.js +969 -0
@@ -0,0 +1,437 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MindMeld CLI - Initialize project for intelligent standards injection
4
+ *
5
+ * Usage:
6
+ * mindmeld init # Initialize for solo/private use
7
+ * mindmeld init --team # Initialize with team collaboration
8
+ * mindmeld init /path/to/project
9
+ *
10
+ * @equilateral_ai/mindmeld v3.0.0
11
+ */
12
+
13
+ const fs = require('fs').promises;
14
+ const path = require('path');
15
+ const { exec } = require('child_process');
16
+ const { promisify } = require('util');
17
+
18
+ const execAsync = promisify(exec);
19
+
20
+ // Parse CLI arguments
21
+ function parseArgs(args) {
22
+ const parsed = {
23
+ command: null,
24
+ projectPath: null,
25
+ team: false,
26
+ format: 'raw',
27
+ since: '7d',
28
+ commits: 10,
29
+ dryRun: false,
30
+ help: false
31
+ };
32
+
33
+ for (let i = 0; i < args.length; i++) {
34
+ const arg = args[i];
35
+ if (arg === '--team') parsed.team = true;
36
+ else if (arg === '--dry-run') parsed.dryRun = true;
37
+ else if (arg === '--help' || arg === '-h') parsed.help = true;
38
+ else if (arg === '--format' && args[i + 1]) { parsed.format = args[++i]; }
39
+ else if (arg === '--path' && args[i + 1]) { parsed.projectPath = args[++i]; }
40
+ else if (arg === '--since' && args[i + 1]) { parsed.since = args[++i]; }
41
+ else if (arg === '--commits' && args[i + 1]) { parsed.commits = parseInt(args[++i]); }
42
+ else if (['init', 'inject', 'harvest'].includes(arg)) parsed.command = arg;
43
+ else if (!arg.startsWith('-') && !parsed.command) parsed.command = arg;
44
+ else if (!arg.startsWith('-') && !parsed.projectPath) parsed.projectPath = arg;
45
+ }
46
+
47
+ // Default command is 'init'
48
+ if (!parsed.command) parsed.command = 'init';
49
+
50
+ return parsed;
51
+ }
52
+
53
+ function showHelp() {
54
+ console.log(`
55
+ MindMeld - Intelligent Standards Injection for AI Coding Tools
56
+
57
+ Usage:
58
+ mindmeld <command> [options]
59
+
60
+ Commands:
61
+ init [path] Initialize project for MindMeld
62
+ inject Generate context-aware standards for any AI tool
63
+ harvest Manually capture patterns from recent git history
64
+
65
+ Options:
66
+ --team Enable team collaboration (init only)
67
+ --format <type> Output format: raw, cursorrules, windsurfrules, aider, claude
68
+ --path <dir> Project path (default: current directory)
69
+ --help, -h Show this help message
70
+
71
+ Examples:
72
+ mindmeld init --team # Init with team collaboration
73
+ mindmeld inject --format cursorrules # Update .cursorrules
74
+ mindmeld inject --format windsurfrules # Update .windsurfrules
75
+ mindmeld inject --format aider # Update aider conventions
76
+ mindmeld inject # Raw markdown to stdout
77
+ mindmeld inject | ollama run qwen3-coder # Pipe to local model
78
+ mindmeld harvest # Capture patterns from git diff
79
+
80
+ Works with: Claude Code, Cursor, Windsurf, Codex CLI, Aider, Ollama, LM Studio
81
+
82
+ Learn more: https://mindmeld.dev
83
+ `);
84
+ }
85
+
86
+ async function initProject(projectPath, options = {}) {
87
+ projectPath = projectPath || process.cwd();
88
+
89
+ console.log(`\n🎯 Initializing MindMeld for: ${projectPath}\n`);
90
+
91
+ if (options.team) {
92
+ console.log(' Mode: Team collaboration\n');
93
+ } else {
94
+ console.log(' Mode: Private (solo)\n');
95
+ }
96
+
97
+ // 1. Check if already initialized
98
+ const mindmeldDir = path.join(projectPath, '.mindmeld');
99
+ const configPath = path.join(mindmeldDir, 'config.json');
100
+
101
+ try {
102
+ await fs.access(configPath);
103
+ console.log('⚠️ Project already initialized!');
104
+ console.log(` Config exists at: ${configPath}\n`);
105
+
106
+ const answer = await promptYesNo('Reinitialize? (y/n): ');
107
+ if (!answer) {
108
+ console.log('Aborted.');
109
+ process.exit(0);
110
+ }
111
+ } catch {
112
+ // Not initialized, continue
113
+ }
114
+
115
+ // 2. Get project name
116
+ const projectName = path.basename(projectPath);
117
+ const projectId = projectName.toLowerCase().replace(/[^a-z0-9]+/g, '-');
118
+
119
+ // 3. Discover collaborators from git
120
+ let collaborators = [];
121
+
122
+ try {
123
+ const { stdout } = await execAsync(
124
+ 'git log --format="%an|%ae" | sort | uniq -c | sort -rn | head -10',
125
+ { cwd: projectPath }
126
+ );
127
+
128
+ const lines = stdout.trim().split('\n');
129
+ for (const line of lines) {
130
+ const match = line.trim().match(/^\s*(\d+)\s+(.+)\|(.+)$/);
131
+ if (match) {
132
+ const [, commits, name, email] = match;
133
+ if (parseInt(commits) >= 3) {
134
+ collaborators.push({
135
+ userId: email.split('@')[0].toLowerCase().replace(/[^a-z0-9]/g, ''),
136
+ name: name.trim(),
137
+ email: email.trim(),
138
+ role: 'collaborator',
139
+ source: 'git',
140
+ commits: parseInt(commits)
141
+ });
142
+ }
143
+ }
144
+ }
145
+
146
+ if (collaborators.length > 0) {
147
+ console.log('📋 Discovered collaborators from git history:\n');
148
+ collaborators.forEach((c, i) => {
149
+ console.log(` ${i + 1}. ${c.name} <${c.email}> (${c.commits} commits)`);
150
+ });
151
+ console.log('');
152
+ }
153
+ } catch (error) {
154
+ console.log('ℹ️ No git history found (not a git repo or no commits)\n');
155
+ }
156
+
157
+ // 4. Create .mindmeld directory
158
+ await fs.mkdir(mindmeldDir, { recursive: true });
159
+
160
+ // 5. Create config.json
161
+ const config = {
162
+ projectId,
163
+ projectName,
164
+ created: new Date().toISOString(),
165
+ collaborators,
166
+ private: !options.team,
167
+ team: options.team,
168
+ externalUsersAllowed: false,
169
+ mindmeldVersion: '3.0.0'
170
+ };
171
+
172
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2));
173
+
174
+ console.log('✅ MindMeld initialized!\n');
175
+ console.log(` Config: ${configPath}`);
176
+ console.log(` Project ID: ${projectId}`);
177
+ console.log(` Mode: ${options.team ? 'Team' : 'Private'}`);
178
+ console.log(` Collaborators: ${collaborators.length}`);
179
+ console.log('');
180
+
181
+ // 6. Check for community standards
182
+ const standardsDir = path.join(projectPath, '.equilateral-standards');
183
+
184
+ try {
185
+ await fs.access(standardsDir);
186
+ console.log('ℹ️ Community standards (.equilateral-standards) available');
187
+ } catch {
188
+ // Try to clone the community standards repo
189
+ try {
190
+ await execAsync(
191
+ 'git clone https://github.com/Equilateral-AI/EquilateralAgents-Community-Standards.git .equilateral-standards',
192
+ { cwd: projectPath }
193
+ );
194
+ console.log('✅ Cloned community standards repo');
195
+ } catch {
196
+ console.log('ℹ️ Community standards not available (clone from:');
197
+ console.log(' https://github.com/Equilateral-AI/EquilateralAgents-Community-Standards)');
198
+ console.log(' Local patterns will still be captured in .mindmeld/');
199
+ }
200
+ }
201
+
202
+ // 7. Bootstrap: harvest patterns from git history and promote to standards
203
+ await bootstrapFromHistory(projectPath, { team: options.team });
204
+
205
+ // 8. Configure Claude Code hooks
206
+ await configureClaudeHooks(projectPath);
207
+
208
+ // 9. Register with API if team mode
209
+ if (options.team) {
210
+ console.log('\n📡 Team mode enabled.');
211
+ console.log(' Sign in at https://app.mindmeld.dev to connect this project.');
212
+ console.log(' Your coding sessions will contribute to team-wide standards.\n');
213
+ }
214
+
215
+ // 10. Summary
216
+ console.log('\n🚀 Next steps:');
217
+ console.log(' 1. Start a Claude Code session in this project');
218
+ console.log(' 2. MindMeld hooks will inject relevant standards automatically');
219
+ console.log(' 3. Patterns from your sessions will be harvested and validated');
220
+ if (options.team) {
221
+ console.log(' 4. Sign in at https://app.mindmeld.dev to manage team standards');
222
+ }
223
+ console.log('');
224
+ }
225
+
226
+ /**
227
+ * Bootstrap: scan 90 days of git history, detect patterns, promote to standards
228
+ */
229
+ async function bootstrapFromHistory(projectPath, options = {}) {
230
+ console.log('\n📊 Bootstrapping from git history...\n');
231
+
232
+ try {
233
+ const { getGitHistory, detectPatterns, savePatterns, promotePatterns, harvestPlans, promoteDecisions } = require('./harvest');
234
+
235
+ // Get extended git history
236
+ const gitHistory = await getGitHistory(projectPath, { since: '90d', commits: 50 });
237
+ const patterns = detectPatterns(gitHistory);
238
+
239
+ if (patterns.length === 0) {
240
+ console.log(' No patterns detected in git history.');
241
+ console.log(' Standards will be populated as you code.\n');
242
+ return;
243
+ }
244
+
245
+ // Save raw patterns
246
+ await savePatterns(projectPath, patterns);
247
+
248
+ // Promote high-confidence patterns to provisional standards
249
+ const promoted = await promotePatterns(projectPath, patterns, { threshold: 0.5 });
250
+
251
+ console.log(` Detected ${patterns.length} pattern(s) from git history`);
252
+ if (promoted.length > 0) {
253
+ console.log(` Promoted ${promoted.length} to provisional standards:`);
254
+ for (const p of promoted) {
255
+ console.log(` - ${p.pattern.element} (${(p.pattern.confidence * 100).toFixed(0)}% confidence)`);
256
+ }
257
+ }
258
+
259
+ // Harvest decisions from Claude Code plan files
260
+ const planDecisions = await harvestPlans(projectPath);
261
+ if (planDecisions.length > 0) {
262
+ const promotedDecisions = await promoteDecisions(projectPath, planDecisions);
263
+ console.log(` Found ${planDecisions.length} decision(s) from session plans`);
264
+ if (promotedDecisions.length > 0) {
265
+ console.log(` Promoted ${promotedDecisions.length} to .mindmeld/decisions/:`);
266
+ for (const d of promotedDecisions) {
267
+ console.log(` - ${d.decision.element}`);
268
+ }
269
+ }
270
+ }
271
+
272
+ console.log('');
273
+ } catch (error) {
274
+ if (error.message && error.message.includes('not a git repository')) {
275
+ console.log(' No git history available (not a git repo).\n');
276
+ } else {
277
+ console.log(` Bootstrap skipped: ${error.message}\n`);
278
+ }
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Configure Claude Code hooks in .claude/settings.json
284
+ * This wires up MindMeld's session-start and pre-compact hooks
285
+ */
286
+ async function configureClaudeHooks(projectPath) {
287
+ const claudeDir = path.join(projectPath, '.claude');
288
+ const settingsPath = path.join(claudeDir, 'settings.json');
289
+
290
+ // Resolve hook paths from installed package location
291
+ const packageRoot = path.resolve(__dirname, '..');
292
+ const sessionStartHook = path.join(packageRoot, 'hooks', 'session-start.js');
293
+ const preCompactHook = path.join(packageRoot, 'hooks', 'pre-compact.js');
294
+
295
+ // Verify hooks exist
296
+ try {
297
+ await fs.access(sessionStartHook);
298
+ await fs.access(preCompactHook);
299
+ } catch {
300
+ console.log('⚠️ Hook scripts not found in package. Skipping hook configuration.');
301
+ console.log(` Expected at: ${packageRoot}/hooks/`);
302
+ return;
303
+ }
304
+
305
+ // MindMeld hook definitions
306
+ const mindmeldHooks = {
307
+ SessionStart: [
308
+ {
309
+ hooks: [
310
+ {
311
+ type: 'command',
312
+ command: `node "${sessionStartHook}"`,
313
+ timeout: 5
314
+ }
315
+ ]
316
+ }
317
+ ],
318
+ PreCompact: [
319
+ {
320
+ hooks: [
321
+ {
322
+ type: 'command',
323
+ command: `node "${preCompactHook}"`,
324
+ timeout: 30
325
+ }
326
+ ]
327
+ }
328
+ ]
329
+ };
330
+
331
+ // Create .claude directory
332
+ await fs.mkdir(claudeDir, { recursive: true });
333
+
334
+ // Load existing settings if present
335
+ let settings = {};
336
+ try {
337
+ const existing = await fs.readFile(settingsPath, 'utf-8');
338
+ settings = JSON.parse(existing);
339
+ } catch {
340
+ // No existing settings, start fresh
341
+ }
342
+
343
+ // Merge hooks (preserve existing non-MindMeld hooks)
344
+ if (!settings.hooks) {
345
+ settings.hooks = {};
346
+ }
347
+
348
+ // Check if MindMeld hooks already configured
349
+ const hasSessionStart = (settings.hooks.SessionStart || []).some(h =>
350
+ h.hooks?.some(hk => hk.command?.includes('mindmeld') || hk.command?.includes('session-start'))
351
+ );
352
+ const hasPreCompact = (settings.hooks.PreCompact || []).some(h =>
353
+ h.hooks?.some(hk => hk.command?.includes('mindmeld') || hk.command?.includes('pre-compact'))
354
+ );
355
+
356
+ if (hasSessionStart && hasPreCompact) {
357
+ console.log('ℹ️ Claude Code hooks already configured');
358
+ return;
359
+ }
360
+
361
+ // Add MindMeld hooks (append to existing, don't replace)
362
+ if (!hasSessionStart) {
363
+ settings.hooks.SessionStart = [
364
+ ...(settings.hooks.SessionStart || []),
365
+ ...mindmeldHooks.SessionStart
366
+ ];
367
+ }
368
+ if (!hasPreCompact) {
369
+ settings.hooks.PreCompact = [
370
+ ...(settings.hooks.PreCompact || []),
371
+ ...mindmeldHooks.PreCompact
372
+ ];
373
+ }
374
+
375
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
376
+
377
+ console.log('✅ Claude Code hooks configured');
378
+ console.log(` SessionStart: ${sessionStartHook}`);
379
+ console.log(` PreCompact: ${preCompactHook}`);
380
+ }
381
+
382
+ async function promptYesNo(question) {
383
+ process.stdout.write(question);
384
+
385
+ return new Promise((resolve) => {
386
+ process.stdin.once('data', (data) => {
387
+ const answer = data.toString().trim().toLowerCase();
388
+ resolve(answer === 'y' || answer === 'yes');
389
+ });
390
+ });
391
+ }
392
+
393
+ // Main
394
+ const args = parseArgs(process.argv.slice(2));
395
+
396
+ if (args.help && !args.command) {
397
+ showHelp();
398
+ process.exit(0);
399
+ }
400
+
401
+ if (args.command === 'init') {
402
+ if (args.help) { showHelp(); process.exit(0); }
403
+ initProject(args.projectPath, { team: args.team })
404
+ .then(() => process.exit(0))
405
+ .catch(error => {
406
+ console.error('\n❌ Error:', error.message);
407
+ process.exit(1);
408
+ });
409
+ } else if (args.command === 'inject') {
410
+ const { inject, showInjectHelp } = require('./inject');
411
+ if (args.help) {
412
+ showInjectHelp();
413
+ process.exit(0);
414
+ }
415
+ inject({ format: args.format, path: args.projectPath })
416
+ .then(() => process.exit(0))
417
+ .catch(error => {
418
+ console.error('\n❌ Error:', error.message);
419
+ process.exit(1);
420
+ });
421
+ } else if (args.command === 'harvest') {
422
+ const { harvest, showHarvestHelp } = require('./harvest');
423
+ if (args.help) {
424
+ showHarvestHelp();
425
+ process.exit(0);
426
+ }
427
+ harvest({ path: args.projectPath, since: args.since, commits: args.commits, dryRun: args.dryRun })
428
+ .then(() => process.exit(0))
429
+ .catch(error => {
430
+ console.error('\n❌ Error:', error.message);
431
+ process.exit(1);
432
+ });
433
+ } else {
434
+ console.error(`Unknown command: ${args.command}`);
435
+ console.error('Run "mindmeld --help" for usage.');
436
+ process.exit(1);
437
+ }