@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.
- package/README.md +300 -0
- package/hooks/README.md +494 -0
- package/hooks/pre-compact.js +392 -0
- package/hooks/session-start.js +264 -0
- package/package.json +90 -0
- package/scripts/harvest.js +561 -0
- package/scripts/init-project.js +437 -0
- package/scripts/inject.js +388 -0
- package/src/collaboration/CollaborationPrompt.js +460 -0
- package/src/core/AlertEngine.js +813 -0
- package/src/core/AlertNotifier.js +363 -0
- package/src/core/CorrelationAnalyzer.js +774 -0
- package/src/core/CurationEngine.js +688 -0
- package/src/core/LLMPatternDetector.js +508 -0
- package/src/core/LoadBearingDetector.js +242 -0
- package/src/core/NotificationService.js +1032 -0
- package/src/core/PatternValidator.js +355 -0
- package/src/core/README.md +160 -0
- package/src/core/RapportOrchestrator.js +446 -0
- package/src/core/RelevanceDetector.js +577 -0
- package/src/core/StandardsIngestion.js +575 -0
- package/src/core/TeamLoadBearingDetector.js +431 -0
- package/src/database/dbOperations.js +105 -0
- package/src/handlers/activity/activityGetMe.js +98 -0
- package/src/handlers/activity/activityGetTeam.js +130 -0
- package/src/handlers/alerts/alertsAcknowledge.js +91 -0
- package/src/handlers/alerts/alertsGet.js +250 -0
- package/src/handlers/collaborators/collaboratorAdd.js +201 -0
- package/src/handlers/collaborators/collaboratorInvite.js +218 -0
- package/src/handlers/collaborators/collaboratorList.js +88 -0
- package/src/handlers/collaborators/collaboratorRemove.js +127 -0
- package/src/handlers/collaborators/inviteAccept.js +122 -0
- package/src/handlers/context/contextGet.js +57 -0
- package/src/handlers/context/invariantsGet.js +74 -0
- package/src/handlers/context/loopsGet.js +82 -0
- package/src/handlers/context/notesCreate.js +74 -0
- package/src/handlers/context/purposeGet.js +78 -0
- package/src/handlers/correlations/correlationsDeveloperGet.js +226 -0
- package/src/handlers/correlations/correlationsGet.js +93 -0
- package/src/handlers/correlations/correlationsProjectGet.js +161 -0
- package/src/handlers/github/githubConnectionStatus.js +49 -0
- package/src/handlers/github/githubDiscoverPatterns.js +364 -0
- package/src/handlers/github/githubOAuthCallback.js +166 -0
- package/src/handlers/github/githubOAuthStart.js +59 -0
- package/src/handlers/github/githubPatternsReview.js +109 -0
- package/src/handlers/github/githubReposList.js +105 -0
- package/src/handlers/helpers/checkSuperAdmin.js +85 -0
- package/src/handlers/helpers/dbOperations.js +53 -0
- package/src/handlers/helpers/errorHandler.js +49 -0
- package/src/handlers/helpers/index.js +106 -0
- package/src/handlers/helpers/lambdaWrapper.js +60 -0
- package/src/handlers/helpers/responseUtil.js +55 -0
- package/src/handlers/helpers/subscriptionTiers.js +1168 -0
- package/src/handlers/notifications/getPreferences.js +84 -0
- package/src/handlers/notifications/sendNotification.js +170 -0
- package/src/handlers/notifications/updatePreferences.js +316 -0
- package/src/handlers/patterns/patternUsagePost.js +182 -0
- package/src/handlers/patterns/patternViolationPost.js +185 -0
- package/src/handlers/projects/projectCreate.js +107 -0
- package/src/handlers/projects/projectDelete.js +82 -0
- package/src/handlers/projects/projectGet.js +95 -0
- package/src/handlers/projects/projectUpdate.js +118 -0
- package/src/handlers/reports/aiLeverage.js +206 -0
- package/src/handlers/reports/engineeringInvestment.js +132 -0
- package/src/handlers/reports/riskForecast.js +186 -0
- package/src/handlers/reports/standardsRoi.js +162 -0
- package/src/handlers/scheduled/analyzeCorrelations.js +178 -0
- package/src/handlers/scheduled/analyzeGitHistory.js +510 -0
- package/src/handlers/scheduled/generateAlerts.js +135 -0
- package/src/handlers/scheduled/refreshActivity.js +21 -0
- package/src/handlers/scheduled/scanCompliance.js +334 -0
- package/src/handlers/sessions/sessionEndPost.js +180 -0
- package/src/handlers/sessions/sessionStandardsPost.js +135 -0
- package/src/handlers/stripe/addonManagePost.js +240 -0
- package/src/handlers/stripe/billingPortalPost.js +93 -0
- package/src/handlers/stripe/enterpriseCheckoutPost.js +272 -0
- package/src/handlers/stripe/seatsUpdatePost.js +185 -0
- package/src/handlers/stripe/subscriptionCancelDelete.js +169 -0
- package/src/handlers/stripe/subscriptionCreatePost.js +221 -0
- package/src/handlers/stripe/subscriptionUpdatePut.js +163 -0
- package/src/handlers/stripe/webhookPost.js +454 -0
- package/src/handlers/users/cognitoPostConfirmation.js +150 -0
- package/src/handlers/users/userEntitlementsGet.js +89 -0
- package/src/handlers/users/userGet.js +114 -0
- package/src/handlers/webhooks/githubWebhook.js +223 -0
- 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
|
+
}
|