mindlore 0.0.1 → 0.1.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/LICENSE +21 -21
- package/README.md +56 -1
- package/SCHEMA.md +11 -8
- package/hooks/lib/mindlore-common.cjs +72 -0
- package/hooks/mindlore-fts5-sync.cjs +12 -9
- package/hooks/mindlore-index.cjs +10 -12
- package/hooks/mindlore-post-compact.cjs +2 -2
- package/hooks/mindlore-pre-compact.cjs +1 -1
- package/hooks/mindlore-search.cjs +93 -62
- package/hooks/mindlore-session-focus.cjs +2 -2
- package/package.json +1 -1
- package/scripts/init.cjs +125 -10
- package/scripts/mindlore-fts5-index.cjs +7 -10
- package/scripts/mindlore-fts5-search.cjs +3 -6
- package/scripts/mindlore-health-check.cjs +19 -3
- package/scripts/uninstall.cjs +186 -0
- package/templates/SCHEMA.md +224 -0
package/scripts/init.cjs
CHANGED
|
@@ -14,7 +14,7 @@ const path = require('path');
|
|
|
14
14
|
|
|
15
15
|
// ── Constants ──────────────────────────────────────────────────────────
|
|
16
16
|
|
|
17
|
-
const { MINDLORE_DIR, DB_NAME, DIRECTORIES } = require('./lib/constants.cjs');
|
|
17
|
+
const { MINDLORE_DIR, DB_NAME, DIRECTORIES, homedir } = require('./lib/constants.cjs');
|
|
18
18
|
|
|
19
19
|
const TEMPLATE_FILES = ['INDEX.md', 'log.md'];
|
|
20
20
|
|
|
@@ -84,11 +84,51 @@ function copyTemplates(baseDir, packageRoot) {
|
|
|
84
84
|
|
|
85
85
|
// ── Step 3: Create FTS5 database ───────────────────────────────────────
|
|
86
86
|
|
|
87
|
+
function migrateDatabase(dbPath, Database) {
|
|
88
|
+
const db = new Database(dbPath);
|
|
89
|
+
try {
|
|
90
|
+
// Check if FTS5 table has the new schema (7 columns with slug, description, etc.)
|
|
91
|
+
const info = db.pragma('table_info(mindlore_fts)');
|
|
92
|
+
const columns = info.map((r) => r.name);
|
|
93
|
+
if (!columns.includes('slug') || !columns.includes('description')) {
|
|
94
|
+
log('Upgrading FTS5 schema (2 → 7 columns, porter stemmer)...');
|
|
95
|
+
db.exec('DROP TABLE IF EXISTS mindlore_fts');
|
|
96
|
+
db.exec(`
|
|
97
|
+
CREATE VIRTUAL TABLE mindlore_fts
|
|
98
|
+
USING fts5(path UNINDEXED, slug, description, type UNINDEXED, category, title, content, tokenize='porter unicode61');
|
|
99
|
+
`);
|
|
100
|
+
// Clear hashes so full re-index happens
|
|
101
|
+
db.exec('DELETE FROM file_hashes');
|
|
102
|
+
db.close();
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
} catch (_err) {
|
|
106
|
+
// table_info fails on FTS5 virtual tables in some versions — recreate
|
|
107
|
+
db.exec('DROP TABLE IF EXISTS mindlore_fts');
|
|
108
|
+
db.exec(`
|
|
109
|
+
CREATE VIRTUAL TABLE mindlore_fts
|
|
110
|
+
USING fts5(path UNINDEXED, slug, description, type UNINDEXED, category, title, content, tokenize='porter unicode61');
|
|
111
|
+
`);
|
|
112
|
+
db.exec('DELETE FROM file_hashes');
|
|
113
|
+
db.close();
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
db.close();
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
87
120
|
function createDatabase(baseDir) {
|
|
88
121
|
const dbPath = path.join(baseDir, DB_NAME);
|
|
89
122
|
if (fs.existsSync(dbPath)) {
|
|
90
|
-
|
|
91
|
-
return false;
|
|
123
|
+
let Database;
|
|
124
|
+
try { Database = require('better-sqlite3'); } catch (_err) { return false; }
|
|
125
|
+
const migrated = migrateDatabase(dbPath, Database);
|
|
126
|
+
if (migrated) {
|
|
127
|
+
log('FTS5 schema upgraded — run index to rebuild');
|
|
128
|
+
} else {
|
|
129
|
+
log('Database already exists, schema OK');
|
|
130
|
+
}
|
|
131
|
+
return migrated;
|
|
92
132
|
}
|
|
93
133
|
|
|
94
134
|
let Database;
|
|
@@ -105,7 +145,7 @@ function createDatabase(baseDir) {
|
|
|
105
145
|
|
|
106
146
|
db.exec(`
|
|
107
147
|
CREATE VIRTUAL TABLE IF NOT EXISTS mindlore_fts
|
|
108
|
-
USING fts5(path, content, tokenize='unicode61');
|
|
148
|
+
USING fts5(path UNINDEXED, slug, description, type UNINDEXED, category, title, content, tokenize='porter unicode61');
|
|
109
149
|
`);
|
|
110
150
|
|
|
111
151
|
db.exec(`
|
|
@@ -124,7 +164,7 @@ function createDatabase(baseDir) {
|
|
|
124
164
|
|
|
125
165
|
function mergeHooks(packageRoot) {
|
|
126
166
|
const settingsPath = path.join(
|
|
127
|
-
|
|
167
|
+
homedir(),
|
|
128
168
|
'.claude',
|
|
129
169
|
'settings.json'
|
|
130
170
|
);
|
|
@@ -239,7 +279,59 @@ function addSchemaToProjectDocs() {
|
|
|
239
279
|
return false;
|
|
240
280
|
}
|
|
241
281
|
|
|
242
|
-
// ── Step 6:
|
|
282
|
+
// ── Step 6: Register skills ────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
function registerSkills(packageRoot, plugin) {
|
|
285
|
+
const skillsDir = path.join(homedir(), '.claude', 'skills');
|
|
286
|
+
ensureDir(skillsDir);
|
|
287
|
+
|
|
288
|
+
if (!plugin.skills || plugin.skills.length === 0) return 0;
|
|
289
|
+
|
|
290
|
+
let added = 0;
|
|
291
|
+
for (const skill of plugin.skills) {
|
|
292
|
+
const skillSrcDir = path.join(packageRoot, path.dirname(skill.path));
|
|
293
|
+
const skillDestDir = path.join(skillsDir, skill.name);
|
|
294
|
+
|
|
295
|
+
ensureDir(skillDestDir);
|
|
296
|
+
const entries = fs.readdirSync(skillSrcDir, { withFileTypes: true });
|
|
297
|
+
for (const entry of entries) {
|
|
298
|
+
if (!entry.isFile()) continue;
|
|
299
|
+
fs.copyFileSync(
|
|
300
|
+
path.join(skillSrcDir, entry.name),
|
|
301
|
+
path.join(skillDestDir, entry.name)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
added++;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return added;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ── Step 7: Install better-sqlite3 if needed ──────────────────────────
|
|
311
|
+
|
|
312
|
+
function ensureBetterSqlite3() {
|
|
313
|
+
try {
|
|
314
|
+
require('better-sqlite3');
|
|
315
|
+
return true;
|
|
316
|
+
} catch (_err) {
|
|
317
|
+
try {
|
|
318
|
+
const { execSync } = require('child_process');
|
|
319
|
+
log('Installing better-sqlite3 (native dependency)...');
|
|
320
|
+
execSync('npm install better-sqlite3 --no-save', {
|
|
321
|
+
cwd: process.cwd(),
|
|
322
|
+
stdio: 'pipe',
|
|
323
|
+
timeout: 120000,
|
|
324
|
+
});
|
|
325
|
+
return true;
|
|
326
|
+
} catch (_installErr) {
|
|
327
|
+
log('WARNING: Could not install better-sqlite3. FTS5 search disabled.');
|
|
328
|
+
log(' Run manually: npm install better-sqlite3');
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ── Step 8: Add .mindlore/ to .gitignore ───────────────────────────────
|
|
243
335
|
|
|
244
336
|
function addToGitignore() {
|
|
245
337
|
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
@@ -263,9 +355,15 @@ function main() {
|
|
|
263
355
|
const args = process.argv.slice(2);
|
|
264
356
|
const command = args[0];
|
|
265
357
|
|
|
358
|
+
if (command === 'uninstall') {
|
|
359
|
+
require('./uninstall.cjs');
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
266
363
|
if (command && command !== 'init') {
|
|
267
364
|
console.log(`Unknown command: ${command}`);
|
|
268
365
|
console.log('Usage: npx mindlore init [--recommended]');
|
|
366
|
+
console.log(' npx mindlore uninstall [--all]');
|
|
269
367
|
process.exit(1);
|
|
270
368
|
}
|
|
271
369
|
|
|
@@ -291,11 +389,20 @@ function main() {
|
|
|
291
389
|
: 'All templates already in place'
|
|
292
390
|
);
|
|
293
391
|
|
|
294
|
-
// Step 3:
|
|
392
|
+
// Step 3: better-sqlite3 (before DB creation so it's available)
|
|
393
|
+
ensureBetterSqlite3();
|
|
394
|
+
|
|
395
|
+
// Step 4: Database
|
|
295
396
|
const dbCreated = createDatabase(baseDir);
|
|
296
397
|
log(dbCreated ? 'Created FTS5 database' : 'Database already exists');
|
|
297
398
|
|
|
298
|
-
//
|
|
399
|
+
// Read plugin.json once for hooks + skills
|
|
400
|
+
const pluginPath = path.join(packageRoot, 'plugin.json');
|
|
401
|
+
const plugin = fs.existsSync(pluginPath)
|
|
402
|
+
? JSON.parse(fs.readFileSync(pluginPath, 'utf8'))
|
|
403
|
+
: {};
|
|
404
|
+
|
|
405
|
+
// Step 5: Hooks
|
|
299
406
|
const hooksAdded = mergeHooks(packageRoot);
|
|
300
407
|
if (typeof hooksAdded === 'number' && hooksAdded > 0) {
|
|
301
408
|
log(`Registered ${hooksAdded} hooks in ~/.claude/settings.json`);
|
|
@@ -303,7 +410,7 @@ function main() {
|
|
|
303
410
|
log('Hooks already registered (or settings.json not found)');
|
|
304
411
|
}
|
|
305
412
|
|
|
306
|
-
// Step
|
|
413
|
+
// Step 6: SCHEMA.md in projectDocFiles
|
|
307
414
|
const schemaAdded = addSchemaToProjectDocs();
|
|
308
415
|
log(
|
|
309
416
|
schemaAdded
|
|
@@ -311,7 +418,15 @@ function main() {
|
|
|
311
418
|
: 'SCHEMA.md already in project settings'
|
|
312
419
|
);
|
|
313
420
|
|
|
314
|
-
// Step
|
|
421
|
+
// Step 7: Skills
|
|
422
|
+
const skillsAdded = registerSkills(packageRoot, plugin);
|
|
423
|
+
log(
|
|
424
|
+
skillsAdded > 0
|
|
425
|
+
? `Registered ${skillsAdded} skills in ~/.claude/skills/`
|
|
426
|
+
: 'Skills already registered'
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
// Step 8: .gitignore
|
|
315
430
|
const gitignoreAdded = addToGitignore();
|
|
316
431
|
log(
|
|
317
432
|
gitignoreAdded
|
|
@@ -13,7 +13,7 @@ const path = require('path');
|
|
|
13
13
|
// ── Constants ──────────────────────────────────────────────────────────
|
|
14
14
|
|
|
15
15
|
const { DB_NAME } = require('./lib/constants.cjs');
|
|
16
|
-
const { sha256, getAllMdFiles } = require('../hooks/lib/mindlore-common.cjs');
|
|
16
|
+
const { sha256, getAllMdFiles, openDatabase, parseFrontmatter, extractFtsMetadata, SQL_FTS_INSERT } = require('../hooks/lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
// ── Main ───────────────────────────────────────────────────────────────
|
|
19
19
|
|
|
@@ -26,17 +26,12 @@ function main() {
|
|
|
26
26
|
process.exit(1);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Database = require('better-sqlite3');
|
|
32
|
-
} catch (_err) {
|
|
29
|
+
const db = openDatabase(dbPath);
|
|
30
|
+
if (!db) {
|
|
33
31
|
console.error(' better-sqlite3 not installed. Run: npm install better-sqlite3');
|
|
34
32
|
process.exit(1);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
const db = new Database(dbPath);
|
|
38
|
-
db.pragma('journal_mode = WAL');
|
|
39
|
-
|
|
40
35
|
// Prepare statements
|
|
41
36
|
const getHash = db.prepare('SELECT content_hash FROM file_hashes WHERE path = ?');
|
|
42
37
|
const upsertHash = db.prepare(`
|
|
@@ -47,7 +42,7 @@ function main() {
|
|
|
47
42
|
last_indexed = excluded.last_indexed
|
|
48
43
|
`);
|
|
49
44
|
const deleteFts = db.prepare('DELETE FROM mindlore_fts WHERE path = ?');
|
|
50
|
-
const insertFts = db.prepare(
|
|
45
|
+
const insertFts = db.prepare(SQL_FTS_INSERT);
|
|
51
46
|
|
|
52
47
|
// Get all .md files
|
|
53
48
|
const mdFiles = getAllMdFiles(baseDir);
|
|
@@ -71,8 +66,10 @@ function main() {
|
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
// Update FTS5
|
|
69
|
+
const { meta, body } = parseFrontmatter(content);
|
|
70
|
+
const { slug, description, type, category, title } = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
74
71
|
deleteFts.run(filePath);
|
|
75
|
-
insertFts.run(filePath,
|
|
72
|
+
insertFts.run(filePath, slug, description, type, category, title, body);
|
|
76
73
|
|
|
77
74
|
// Update hash
|
|
78
75
|
upsertHash.run(filePath, hash, now);
|
|
@@ -13,6 +13,7 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
|
|
15
15
|
const { DB_NAME } = require('./lib/constants.cjs');
|
|
16
|
+
const { openDatabase } = require('../hooks/lib/mindlore-common.cjs');
|
|
16
17
|
const MAX_RESULTS = 3;
|
|
17
18
|
|
|
18
19
|
// ── Helpers ────────────────────────────────────────────────────────────
|
|
@@ -46,16 +47,12 @@ function main() {
|
|
|
46
47
|
process.exit(1);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Database = require('better-sqlite3');
|
|
52
|
-
} catch (_err) {
|
|
50
|
+
const db = openDatabase(dbPath, { readonly: true });
|
|
51
|
+
if (!db) {
|
|
53
52
|
console.error(' better-sqlite3 not installed.');
|
|
54
53
|
process.exit(1);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
const db = new Database(dbPath, { readonly: true });
|
|
58
|
-
|
|
59
56
|
try {
|
|
60
57
|
// Sanitize query for FTS5 (escape special chars)
|
|
61
58
|
const sanitized = query.replace(/['"(){}[\]*:^~!]/g, ' ').trim();
|
|
@@ -116,10 +116,10 @@ class HealthChecker {
|
|
|
116
116
|
}
|
|
117
117
|
const content = fs.readFileSync(indexPath, 'utf8');
|
|
118
118
|
const lines = content.trim().split('\n');
|
|
119
|
-
if (lines.length >
|
|
119
|
+
if (lines.length > 60) {
|
|
120
120
|
return {
|
|
121
121
|
warn: true,
|
|
122
|
-
detail: `${lines.length} lines (should be ~15-
|
|
122
|
+
detail: `${lines.length} lines (should be ~15-60, consider trimming)`,
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
return { ok: true, detail: `${lines.length} lines` };
|
|
@@ -147,9 +147,25 @@ class HealthChecker {
|
|
|
147
147
|
const hashResult = db
|
|
148
148
|
.prepare('SELECT count(*) as cnt FROM file_hashes')
|
|
149
149
|
.get();
|
|
150
|
+
|
|
151
|
+
// Verify 7-column schema (slug, description, type, category, title, content + path)
|
|
152
|
+
let schemaOk = true;
|
|
153
|
+
try {
|
|
154
|
+
db.prepare('SELECT slug, description, category, title FROM mindlore_fts LIMIT 0').run();
|
|
155
|
+
} catch (_err) {
|
|
156
|
+
schemaOk = false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!schemaOk) {
|
|
160
|
+
return {
|
|
161
|
+
warn: true,
|
|
162
|
+
detail: `${result.cnt} indexed, ${hashResult.cnt} hashes — OLD SCHEMA (run: npx mindlore init to upgrade)`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
150
166
|
return {
|
|
151
167
|
ok: true,
|
|
152
|
-
detail: `${result.cnt} indexed, ${hashResult.cnt} hashes`,
|
|
168
|
+
detail: `${result.cnt} indexed, ${hashResult.cnt} hashes, 7-col schema`,
|
|
153
169
|
};
|
|
154
170
|
} catch (err) {
|
|
155
171
|
return { ok: false, detail: `FTS5 error: ${err.message}` };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* mindlore uninstall — Remove Mindlore hooks, skills, and optionally project data.
|
|
6
|
+
*
|
|
7
|
+
* Usage: npx mindlore uninstall [--all]
|
|
8
|
+
*
|
|
9
|
+
* --all: also remove .mindlore/ project data (without flag, only hooks + skills)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { homedir } = require('./lib/constants.cjs');
|
|
15
|
+
|
|
16
|
+
function log(msg) {
|
|
17
|
+
console.log(` ${msg}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── Remove hooks from settings.json ────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
function removeHooks() {
|
|
23
|
+
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
|
|
24
|
+
|
|
25
|
+
if (!fs.existsSync(settingsPath)) {
|
|
26
|
+
log('No settings.json found, skipping hooks');
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let settings;
|
|
31
|
+
try {
|
|
32
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
33
|
+
} catch (_err) {
|
|
34
|
+
log('Could not parse settings.json, skipping hooks');
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!settings.hooks) return 0;
|
|
39
|
+
|
|
40
|
+
let removed = 0;
|
|
41
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
42
|
+
const entries = settings.hooks[event];
|
|
43
|
+
if (!Array.isArray(entries)) continue;
|
|
44
|
+
|
|
45
|
+
const filtered = entries.filter((entry) => {
|
|
46
|
+
const hooks = entry.hooks || [];
|
|
47
|
+
const hasMindlore = hooks.some(
|
|
48
|
+
(h) => (h.command || '').includes('mindlore-')
|
|
49
|
+
);
|
|
50
|
+
// Also check flat format (legacy)
|
|
51
|
+
const flatMindlore = (entry.command || '').includes('mindlore-');
|
|
52
|
+
|
|
53
|
+
if (hasMindlore || flatMindlore) {
|
|
54
|
+
removed++;
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
settings.hooks[event] = filtered;
|
|
61
|
+
|
|
62
|
+
// Clean up empty arrays
|
|
63
|
+
if (settings.hooks[event].length === 0) {
|
|
64
|
+
delete settings.hooks[event];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (removed > 0) {
|
|
69
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return removed;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Remove skills from ~/.claude/skills/ ───────────────────────────────
|
|
76
|
+
|
|
77
|
+
function removeSkills() {
|
|
78
|
+
const skillsDir = path.join(homedir(), '.claude', 'skills');
|
|
79
|
+
if (!fs.existsSync(skillsDir)) return 0;
|
|
80
|
+
|
|
81
|
+
const mindloreSkills = fs
|
|
82
|
+
.readdirSync(skillsDir)
|
|
83
|
+
.filter((d) => d.startsWith('mindlore-'));
|
|
84
|
+
|
|
85
|
+
let removed = 0;
|
|
86
|
+
for (const skill of mindloreSkills) {
|
|
87
|
+
const skillPath = path.join(skillsDir, skill);
|
|
88
|
+
fs.rmSync(skillPath, { recursive: true, force: true });
|
|
89
|
+
removed++;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return removed;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── Remove SCHEMA.md from projectDocFiles ──────────────────────────────
|
|
96
|
+
|
|
97
|
+
function removeFromProjectDocs() {
|
|
98
|
+
const projectSettingsPath = path.join(process.cwd(), '.claude', 'settings.json');
|
|
99
|
+
if (!fs.existsSync(projectSettingsPath)) return false;
|
|
100
|
+
|
|
101
|
+
let settings;
|
|
102
|
+
try {
|
|
103
|
+
settings = JSON.parse(fs.readFileSync(projectSettingsPath, 'utf8'));
|
|
104
|
+
} catch (_err) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!settings.projectDocFiles) return false;
|
|
109
|
+
|
|
110
|
+
const before = settings.projectDocFiles.length;
|
|
111
|
+
settings.projectDocFiles = settings.projectDocFiles.filter(
|
|
112
|
+
(p) => !p.includes('mindlore')
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (settings.projectDocFiles.length < before) {
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
projectSettingsPath,
|
|
118
|
+
JSON.stringify(settings, null, 2),
|
|
119
|
+
'utf8'
|
|
120
|
+
);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ── Remove .mindlore/ project data ─────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
function removeProjectData() {
|
|
129
|
+
const mindloreDir = path.join(process.cwd(), '.mindlore');
|
|
130
|
+
if (!fs.existsSync(mindloreDir)) {
|
|
131
|
+
log('No .mindlore/ directory in current project');
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fs.rmSync(mindloreDir, { recursive: true, force: true });
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── Main ───────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
function main() {
|
|
142
|
+
const args = process.argv.slice(2);
|
|
143
|
+
const removeAll = args.includes('--all');
|
|
144
|
+
|
|
145
|
+
console.log('\n Mindlore — Uninstall\n');
|
|
146
|
+
|
|
147
|
+
// Hooks
|
|
148
|
+
const hooksRemoved = removeHooks();
|
|
149
|
+
log(
|
|
150
|
+
hooksRemoved > 0
|
|
151
|
+
? `Removed ${hooksRemoved} hooks from ~/.claude/settings.json`
|
|
152
|
+
: 'No hooks found'
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Skills
|
|
156
|
+
const skillsRemoved = removeSkills();
|
|
157
|
+
log(
|
|
158
|
+
skillsRemoved > 0
|
|
159
|
+
? `Removed ${skillsRemoved} skills from ~/.claude/skills/`
|
|
160
|
+
: 'No skills found'
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Project doc files
|
|
164
|
+
const docsRemoved = removeFromProjectDocs();
|
|
165
|
+
log(
|
|
166
|
+
docsRemoved
|
|
167
|
+
? 'Removed SCHEMA.md from project settings'
|
|
168
|
+
: 'No project doc references found'
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Project data (only with --all)
|
|
172
|
+
if (removeAll) {
|
|
173
|
+
const dataRemoved = removeProjectData();
|
|
174
|
+
log(
|
|
175
|
+
dataRemoved
|
|
176
|
+
? 'Removed .mindlore/ project data'
|
|
177
|
+
: 'No .mindlore/ directory found'
|
|
178
|
+
);
|
|
179
|
+
} else {
|
|
180
|
+
log('.mindlore/ project data kept (use --all to remove)');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log('\n Done! Mindlore has been uninstalled.\n');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main();
|