mindlore 0.1.0 → 0.2.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 (98) hide show
  1. package/README.md +13 -5
  2. package/SCHEMA.md +60 -4
  3. package/dist/scripts/init.d.ts +10 -0
  4. package/dist/scripts/init.d.ts.map +1 -0
  5. package/dist/scripts/init.js +375 -0
  6. package/dist/scripts/init.js.map +1 -0
  7. package/dist/scripts/lib/constants.d.ts +29 -0
  8. package/dist/scripts/lib/constants.d.ts.map +1 -0
  9. package/dist/scripts/lib/constants.js +58 -0
  10. package/dist/scripts/lib/constants.js.map +1 -0
  11. package/dist/scripts/mindlore-fts5-index.d.ts +9 -0
  12. package/dist/scripts/mindlore-fts5-index.d.ts.map +1 -0
  13. package/dist/scripts/mindlore-fts5-index.js +89 -0
  14. package/dist/scripts/mindlore-fts5-index.js.map +1 -0
  15. package/dist/scripts/mindlore-fts5-search.d.ts +10 -0
  16. package/dist/scripts/mindlore-fts5-search.d.ts.map +1 -0
  17. package/dist/scripts/mindlore-fts5-search.js +108 -0
  18. package/dist/scripts/mindlore-fts5-search.js.map +1 -0
  19. package/dist/scripts/mindlore-health-check.d.ts +10 -0
  20. package/dist/scripts/mindlore-health-check.d.ts.map +1 -0
  21. package/dist/scripts/mindlore-health-check.js +337 -0
  22. package/dist/scripts/mindlore-health-check.js.map +1 -0
  23. package/dist/scripts/uninstall.d.ts +10 -0
  24. package/dist/scripts/uninstall.d.ts.map +1 -0
  25. package/dist/scripts/uninstall.js +143 -0
  26. package/dist/scripts/uninstall.js.map +1 -0
  27. package/dist/tests/compounding.test.d.ts +8 -0
  28. package/dist/tests/compounding.test.d.ts.map +1 -0
  29. package/dist/tests/compounding.test.js +51 -0
  30. package/dist/tests/compounding.test.js.map +1 -0
  31. package/dist/tests/decision.test.d.ts +2 -0
  32. package/dist/tests/decision.test.d.ts.map +1 -0
  33. package/dist/tests/decision.test.js +61 -0
  34. package/dist/tests/decision.test.js.map +1 -0
  35. package/dist/tests/dedup.test.d.ts +2 -0
  36. package/dist/tests/dedup.test.d.ts.map +1 -0
  37. package/dist/tests/dedup.test.js +74 -0
  38. package/dist/tests/dedup.test.js.map +1 -0
  39. package/dist/tests/frontmatter.test.d.ts +2 -0
  40. package/dist/tests/frontmatter.test.d.ts.map +1 -0
  41. package/dist/tests/frontmatter.test.js +90 -0
  42. package/dist/tests/frontmatter.test.js.map +1 -0
  43. package/dist/tests/fts5.test.d.ts +2 -0
  44. package/dist/tests/fts5.test.d.ts.map +1 -0
  45. package/dist/tests/fts5.test.js +95 -0
  46. package/dist/tests/fts5.test.js.map +1 -0
  47. package/dist/tests/helpers/db.d.ts +7 -0
  48. package/dist/tests/helpers/db.d.ts.map +1 -0
  49. package/dist/tests/helpers/db.js +46 -0
  50. package/dist/tests/helpers/db.js.map +1 -0
  51. package/dist/tests/hook-smoke.test.d.ts +2 -0
  52. package/dist/tests/hook-smoke.test.d.ts.map +1 -0
  53. package/dist/tests/hook-smoke.test.js +58 -0
  54. package/dist/tests/hook-smoke.test.js.map +1 -0
  55. package/dist/tests/init.test.d.ts +2 -0
  56. package/dist/tests/init.test.d.ts.map +1 -0
  57. package/dist/tests/init.test.js +85 -0
  58. package/dist/tests/init.test.js.map +1 -0
  59. package/dist/tests/log.test.d.ts +2 -0
  60. package/dist/tests/log.test.d.ts.map +1 -0
  61. package/dist/tests/log.test.js +68 -0
  62. package/dist/tests/log.test.js.map +1 -0
  63. package/dist/tests/read-guard.test.d.ts +2 -0
  64. package/dist/tests/read-guard.test.d.ts.map +1 -0
  65. package/dist/tests/read-guard.test.js +69 -0
  66. package/dist/tests/read-guard.test.js.map +1 -0
  67. package/dist/tests/search-hook.test.d.ts +2 -0
  68. package/dist/tests/search-hook.test.d.ts.map +1 -0
  69. package/dist/tests/search-hook.test.js +108 -0
  70. package/dist/tests/search-hook.test.js.map +1 -0
  71. package/dist/tests/session-focus.test.d.ts +2 -0
  72. package/dist/tests/session-focus.test.d.ts.map +1 -0
  73. package/dist/tests/session-focus.test.js +71 -0
  74. package/dist/tests/session-focus.test.js.map +1 -0
  75. package/dist/tests/uninstall.test.d.ts +2 -0
  76. package/dist/tests/uninstall.test.d.ts.map +1 -0
  77. package/dist/tests/uninstall.test.js +98 -0
  78. package/dist/tests/uninstall.test.js.map +1 -0
  79. package/hooks/lib/mindlore-common.cjs +36 -2
  80. package/hooks/mindlore-decision-detector.cjs +51 -0
  81. package/hooks/mindlore-fts5-sync.cjs +4 -18
  82. package/hooks/mindlore-index.cjs +4 -18
  83. package/hooks/mindlore-read-guard.cjs +62 -0
  84. package/hooks/mindlore-search.cjs +5 -18
  85. package/hooks/mindlore-session-end.cjs +74 -8
  86. package/package.json +19 -7
  87. package/plugin.json +26 -2
  88. package/skills/mindlore-decide/SKILL.md +71 -0
  89. package/skills/mindlore-ingest/SKILL.md +13 -2
  90. package/skills/mindlore-log/SKILL.md +79 -0
  91. package/skills/mindlore-query/SKILL.md +125 -0
  92. package/templates/SCHEMA.md +60 -4
  93. package/scripts/init.cjs +0 -450
  94. package/scripts/lib/constants.cjs +0 -49
  95. package/scripts/mindlore-fts5-index.cjs +0 -112
  96. package/scripts/mindlore-fts5-search.cjs +0 -119
  97. package/scripts/mindlore-health-check.cjs +0 -336
  98. package/scripts/uninstall.cjs +0 -186
@@ -1,119 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mindlore-fts5-search — Search .mindlore/ knowledge base via FTS5.
6
- *
7
- * Usage: node scripts/mindlore-fts5-search.cjs "query" [path-to-mindlore-dir]
8
- *
9
- * Returns top 3 results ranked by BM25 with file path and snippet.
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- const { DB_NAME } = require('./lib/constants.cjs');
16
- const { openDatabase } = require('../hooks/lib/mindlore-common.cjs');
17
- const MAX_RESULTS = 3;
18
-
19
- // ── Helpers ────────────────────────────────────────────────────────────
20
-
21
- function extractHeadings(content, maxHeadings) {
22
- const lines = content.split('\n');
23
- const headings = [];
24
- for (const line of lines) {
25
- if (line.startsWith('#')) {
26
- headings.push(line.replace(/^#+\s*/, '').trim());
27
- if (headings.length >= maxHeadings) break;
28
- }
29
- }
30
- return headings;
31
- }
32
-
33
- // ── Main ───────────────────────────────────────────────────────────────
34
-
35
- function main() {
36
- const query = process.argv[2];
37
- if (!query) {
38
- console.error('Usage: node mindlore-fts5-search.cjs "query" [mindlore-dir]');
39
- process.exit(1);
40
- }
41
-
42
- const baseDir = process.argv[3] || path.join(process.cwd(), '.mindlore');
43
- const dbPath = path.join(baseDir, DB_NAME);
44
-
45
- if (!fs.existsSync(dbPath)) {
46
- console.error(' Database not found. Run: npx mindlore init && npm run index');
47
- process.exit(1);
48
- }
49
-
50
- const db = openDatabase(dbPath, { readonly: true });
51
- if (!db) {
52
- console.error(' better-sqlite3 not installed.');
53
- process.exit(1);
54
- }
55
-
56
- try {
57
- // Sanitize query for FTS5 (escape special chars)
58
- const sanitized = query.replace(/['"(){}[\]*:^~!]/g, ' ').trim();
59
- if (!sanitized) {
60
- console.log(' No valid search terms.');
61
- process.exit(0);
62
- }
63
-
64
- const results = db
65
- .prepare(
66
- `SELECT path, snippet(mindlore_fts, 1, '>>>', '<<<', '...', 40) as snippet,
67
- rank
68
- FROM mindlore_fts
69
- WHERE mindlore_fts MATCH ?
70
- ORDER BY rank
71
- LIMIT ?`
72
- )
73
- .all(sanitized, MAX_RESULTS);
74
-
75
- if (results.length === 0) {
76
- console.log(` No results for: "${query}"`);
77
- process.exit(0);
78
- }
79
-
80
- console.log(`\n Mindlore Search: "${query}" (${results.length} results)\n`);
81
-
82
- for (let i = 0; i < results.length; i++) {
83
- const r = results[i];
84
- const relativePath = path.relative(baseDir, r.path);
85
- const fileName = path.basename(r.path, '.md');
86
-
87
- // Try to get headings from the actual file
88
- let headings = [];
89
- if (fs.existsSync(r.path)) {
90
- const content = fs.readFileSync(r.path, 'utf8');
91
- headings = extractHeadings(content, 2);
92
- }
93
-
94
- console.log(` ${i + 1}. ${relativePath}`);
95
- if (headings.length > 0) {
96
- console.log(` ${headings.join(' > ')}`);
97
- }
98
- console.log(` ${r.snippet || fileName}`);
99
- console.log('');
100
- }
101
- } catch (err) {
102
- // FTS5 query syntax error — try simpler query
103
- if (err.message.includes('fts5')) {
104
- const words = query.split(/\s+/).filter((w) => w.length >= 2);
105
- if (words.length > 0) {
106
- console.error(` Search syntax error. Try simpler terms: ${words.join(' ')}`);
107
- } else {
108
- console.error(` Search error: ${err.message}`);
109
- }
110
- } else {
111
- console.error(` Error: ${err.message}`);
112
- }
113
- process.exit(1);
114
- } finally {
115
- db.close();
116
- }
117
- }
118
-
119
- main();
@@ -1,336 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mindlore-health-check — 16-point structural health check for .mindlore/
6
- *
7
- * Usage: node scripts/mindlore-health-check.cjs [path-to-mindlore-dir]
8
- *
9
- * Exit codes: 0 = healthy, 1 = issues found
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- // ── Constants ──────────────────────────────────────────────────────────
16
-
17
- const { DIRECTORIES, TYPE_TO_DIR } = require('./lib/constants.cjs');
18
-
19
- // ── Helpers ────────────────────────────────────────────────────────────
20
-
21
- function parseFrontmatter(content) {
22
- const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
23
- if (!match) return null;
24
-
25
- const fm = {};
26
- const lines = match[1].split('\n');
27
- for (const line of lines) {
28
- const colonIdx = line.indexOf(':');
29
- if (colonIdx === -1) continue;
30
- const key = line.slice(0, colonIdx).trim();
31
- let value = line.slice(colonIdx + 1).trim();
32
- // Handle arrays
33
- if (value.startsWith('[') && value.endsWith(']')) {
34
- value = value
35
- .slice(1, -1)
36
- .split(',')
37
- .map((s) => s.trim());
38
- }
39
- fm[key] = value;
40
- }
41
- return fm;
42
- }
43
-
44
- // Health check needs ALL .md files (no skip), so pass empty set
45
- function getAllMdFiles(dir) {
46
- return require('../hooks/lib/mindlore-common.cjs').getAllMdFiles(dir, new Set());
47
- }
48
-
49
- // ── Checks ─────────────────────────────────────────────────────────────
50
-
51
- class HealthChecker {
52
- constructor(baseDir) {
53
- this.baseDir = baseDir;
54
- this.results = [];
55
- this.passed = 0;
56
- this.failed = 0;
57
- this.warnings = 0;
58
- }
59
-
60
- check(name, fn) {
61
- try {
62
- const result = fn();
63
- if (result.ok) {
64
- this.passed++;
65
- this.results.push({ name, status: 'PASS', detail: result.detail });
66
- } else if (result.warn) {
67
- this.warnings++;
68
- this.results.push({ name, status: 'WARN', detail: result.detail });
69
- } else {
70
- this.failed++;
71
- this.results.push({ name, status: 'FAIL', detail: result.detail });
72
- }
73
- } catch (err) {
74
- this.failed++;
75
- this.results.push({ name, status: 'FAIL', detail: err.message });
76
- }
77
- }
78
-
79
- // Check 1-9: Directory existence
80
- checkDirectories() {
81
- for (const dir of DIRECTORIES) {
82
- this.check(`Directory: ${dir}/`, () => {
83
- const dirPath = path.join(this.baseDir, dir);
84
- if (fs.existsSync(dirPath)) {
85
- return { ok: true, detail: 'exists' };
86
- }
87
- return { ok: false, detail: 'missing' };
88
- });
89
- }
90
- }
91
-
92
- // Check 10: SCHEMA.md parseable
93
- checkSchema() {
94
- this.check('SCHEMA.md', () => {
95
- const schemaPath = path.join(this.baseDir, 'SCHEMA.md');
96
- if (!fs.existsSync(schemaPath)) {
97
- return { ok: false, detail: 'missing' };
98
- }
99
- const content = fs.readFileSync(schemaPath, 'utf8');
100
- if (content.length < 100) {
101
- return { ok: false, detail: 'too short (corrupted?)' };
102
- }
103
- if (!content.includes('## 1. Identity')) {
104
- return { warn: true, detail: 'may be outdated (missing Identity section)' };
105
- }
106
- return { ok: true, detail: `${content.split('\n').length} lines` };
107
- });
108
- }
109
-
110
- // Check 11: INDEX.md format
111
- checkIndex() {
112
- this.check('INDEX.md format', () => {
113
- const indexPath = path.join(this.baseDir, 'INDEX.md');
114
- if (!fs.existsSync(indexPath)) {
115
- return { ok: false, detail: 'missing' };
116
- }
117
- const content = fs.readFileSync(indexPath, 'utf8');
118
- const lines = content.trim().split('\n');
119
- if (lines.length > 60) {
120
- return {
121
- warn: true,
122
- detail: `${lines.length} lines (should be ~15-60, consider trimming)`,
123
- };
124
- }
125
- return { ok: true, detail: `${lines.length} lines` };
126
- });
127
- }
128
-
129
- // Check 12: Database integrity
130
- checkDatabase() {
131
- this.check('mindlore.db FTS5', () => {
132
- const dbPath = path.join(this.baseDir, 'mindlore.db');
133
- if (!fs.existsSync(dbPath)) {
134
- return { ok: false, detail: 'database missing' };
135
- }
136
-
137
- let Database;
138
- try {
139
- Database = require('better-sqlite3');
140
- } catch (_err) {
141
- return { warn: true, detail: 'better-sqlite3 not available, cannot verify' };
142
- }
143
-
144
- const db = new Database(dbPath, { readonly: true });
145
- try {
146
- const result = db.prepare('SELECT count(*) as cnt FROM mindlore_fts').get();
147
- const hashResult = db
148
- .prepare('SELECT count(*) as cnt FROM file_hashes')
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
-
166
- return {
167
- ok: true,
168
- detail: `${result.cnt} indexed, ${hashResult.cnt} hashes, 7-col schema`,
169
- };
170
- } catch (err) {
171
- return { ok: false, detail: `FTS5 error: ${err.message}` };
172
- } finally {
173
- db.close();
174
- }
175
- });
176
- }
177
-
178
- // Check 13: Orphan files (in .mindlore/ but not in FTS5)
179
- checkOrphans() {
180
- this.check('Orphan files', () => {
181
- const dbPath = path.join(this.baseDir, 'mindlore.db');
182
- if (!fs.existsSync(dbPath)) {
183
- return { warn: true, detail: 'no database, cannot check' };
184
- }
185
-
186
- let Database;
187
- try {
188
- Database = require('better-sqlite3');
189
- } catch (_err) {
190
- return { warn: true, detail: 'better-sqlite3 not available' };
191
- }
192
-
193
- const mdFiles = getAllMdFiles(this.baseDir).filter(
194
- (f) =>
195
- !f.endsWith('INDEX.md') &&
196
- !f.endsWith('SCHEMA.md') &&
197
- !f.endsWith('log.md')
198
- );
199
-
200
- const db = new Database(dbPath, { readonly: true });
201
- try {
202
- const indexed = new Set();
203
- const rows = db.prepare('SELECT path FROM file_hashes').all();
204
- for (const row of rows) {
205
- indexed.add(path.resolve(row.path));
206
- }
207
-
208
- const orphans = mdFiles.filter(
209
- (f) => !indexed.has(path.resolve(f))
210
- );
211
-
212
- if (orphans.length === 0) {
213
- return { ok: true, detail: 'no orphans' };
214
- }
215
- if (orphans.length <= 3) {
216
- return {
217
- warn: true,
218
- detail: `${orphans.length} unindexed: ${orphans.map((f) => path.basename(f)).join(', ')}`,
219
- };
220
- }
221
- return {
222
- ok: false,
223
- detail: `${orphans.length} unindexed files — run: npm run index`,
224
- };
225
- } finally {
226
- db.close();
227
- }
228
- });
229
- }
230
-
231
- // Check 14-16: Frontmatter validation
232
- checkFrontmatter() {
233
- this.check('Frontmatter: slug + type', () => {
234
- const mdFiles = getAllMdFiles(this.baseDir).filter(
235
- (f) =>
236
- !f.endsWith('INDEX.md') &&
237
- !f.endsWith('SCHEMA.md') &&
238
- !f.endsWith('log.md')
239
- );
240
-
241
- let missingSlug = 0;
242
- let missingType = 0;
243
- let wrongDir = 0;
244
-
245
- for (const file of mdFiles) {
246
- const content = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n');
247
- const fm = parseFrontmatter(content);
248
-
249
- if (!fm) {
250
- missingSlug++;
251
- missingType++;
252
- continue;
253
- }
254
-
255
- if (!fm.slug) missingSlug++;
256
- if (!fm.type) {
257
- missingType++;
258
- continue;
259
- }
260
-
261
- // Check type-directory match
262
- const expectedDir = TYPE_TO_DIR[fm.type];
263
- if (expectedDir) {
264
- const parentDir = path.basename(path.dirname(file));
265
- if (parentDir !== expectedDir) {
266
- wrongDir++;
267
- }
268
- }
269
- }
270
-
271
- const issues = [];
272
- if (missingSlug > 0) issues.push(`${missingSlug} missing slug`);
273
- if (missingType > 0) issues.push(`${missingType} missing type`);
274
- if (wrongDir > 0) issues.push(`${wrongDir} type-dir mismatch`);
275
-
276
- if (issues.length === 0) {
277
- return {
278
- ok: true,
279
- detail: `${mdFiles.length} files validated`,
280
- };
281
- }
282
- return {
283
- ok: wrongDir > 0 ? false : undefined,
284
- warn: wrongDir === 0,
285
- detail: issues.join(', '),
286
- };
287
- });
288
- }
289
-
290
- // ── Run all ────────────────────────────────────────────────────────
291
-
292
- run() {
293
- this.checkDirectories();
294
- this.checkSchema();
295
- this.checkIndex();
296
- this.checkDatabase();
297
- this.checkOrphans();
298
- this.checkFrontmatter();
299
- return this;
300
- }
301
-
302
- report() {
303
- console.log('\n Mindlore Health Check\n');
304
-
305
- for (const r of this.results) {
306
- const icon =
307
- r.status === 'PASS' ? '+' : r.status === 'WARN' ? '~' : '-';
308
- console.log(` [${icon}] ${r.name}: ${r.detail}`);
309
- }
310
-
311
- const total = this.passed + this.failed + this.warnings;
312
- console.log(
313
- `\n Score: ${this.passed}/${total} passed, ${this.warnings} warnings, ${this.failed} failed\n`
314
- );
315
-
316
- return this.failed === 0;
317
- }
318
- }
319
-
320
- // ── Main ───────────────────────────────────────────────────────────────
321
-
322
- function main() {
323
- const baseDir = process.argv[2] || path.join(process.cwd(), '.mindlore');
324
-
325
- if (!fs.existsSync(baseDir)) {
326
- console.error(` .mindlore/ not found at: ${baseDir}`);
327
- console.error(' Run: npx mindlore init');
328
- process.exit(1);
329
- }
330
-
331
- const checker = new HealthChecker(baseDir);
332
- const healthy = checker.run().report();
333
- process.exit(healthy ? 0 : 1);
334
- }
335
-
336
- main();
@@ -1,186 +0,0 @@
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();