mindlore 0.2.0 → 0.3.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 +15 -9
- package/SCHEMA.md +15 -2
- package/dist/scripts/init.d.ts +10 -0
- package/dist/scripts/init.d.ts.map +1 -0
- package/dist/scripts/init.js +406 -0
- package/dist/scripts/init.js.map +1 -0
- package/dist/scripts/lib/constants.d.ts +56 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -0
- package/dist/scripts/lib/constants.js +131 -0
- package/dist/scripts/lib/constants.js.map +1 -0
- package/dist/scripts/lib/schemas.d.ts +93 -0
- package/dist/scripts/lib/schemas.d.ts.map +1 -0
- package/dist/scripts/lib/schemas.js +108 -0
- package/dist/scripts/lib/schemas.js.map +1 -0
- package/dist/scripts/mindlore-fts5-index.d.ts +9 -0
- package/dist/scripts/mindlore-fts5-index.d.ts.map +1 -0
- package/dist/scripts/mindlore-fts5-index.js +88 -0
- package/dist/scripts/mindlore-fts5-index.js.map +1 -0
- package/dist/scripts/mindlore-fts5-search.d.ts +10 -0
- package/dist/scripts/mindlore-fts5-search.d.ts.map +1 -0
- package/dist/scripts/mindlore-fts5-search.js +121 -0
- package/dist/scripts/mindlore-fts5-search.js.map +1 -0
- package/dist/scripts/mindlore-health-check.d.ts +10 -0
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -0
- package/dist/scripts/mindlore-health-check.js +337 -0
- package/dist/scripts/mindlore-health-check.js.map +1 -0
- package/dist/scripts/uninstall.d.ts +10 -0
- package/dist/scripts/uninstall.d.ts.map +1 -0
- package/dist/scripts/uninstall.js +153 -0
- package/dist/scripts/uninstall.js.map +1 -0
- package/dist/tests/compounding.test.d.ts +8 -0
- package/dist/tests/compounding.test.d.ts.map +1 -0
- package/dist/tests/compounding.test.js +51 -0
- package/dist/tests/compounding.test.js.map +1 -0
- package/dist/tests/cwd-changed.test.d.ts +2 -0
- package/dist/tests/cwd-changed.test.d.ts.map +1 -0
- package/dist/tests/cwd-changed.test.js +62 -0
- package/dist/tests/cwd-changed.test.js.map +1 -0
- package/dist/tests/decision.test.d.ts +2 -0
- package/dist/tests/decision.test.d.ts.map +1 -0
- package/dist/tests/decision.test.js +61 -0
- package/dist/tests/decision.test.js.map +1 -0
- package/dist/tests/dedup.test.d.ts +2 -0
- package/dist/tests/dedup.test.d.ts.map +1 -0
- package/dist/tests/dedup.test.js +74 -0
- package/dist/tests/dedup.test.js.map +1 -0
- package/dist/tests/dont-repeat.test.d.ts +2 -0
- package/dist/tests/dont-repeat.test.d.ts.map +1 -0
- package/dist/tests/dont-repeat.test.js +100 -0
- package/dist/tests/dont-repeat.test.js.map +1 -0
- package/dist/tests/e2e-pipeline.test.d.ts +2 -0
- package/dist/tests/e2e-pipeline.test.d.ts.map +1 -0
- package/dist/tests/e2e-pipeline.test.js +220 -0
- package/dist/tests/e2e-pipeline.test.js.map +1 -0
- package/dist/tests/evolve.test.d.ts +2 -0
- package/dist/tests/evolve.test.d.ts.map +1 -0
- package/dist/tests/evolve.test.js +105 -0
- package/dist/tests/evolve.test.js.map +1 -0
- package/dist/tests/explore.test.d.ts +2 -0
- package/dist/tests/explore.test.d.ts.map +1 -0
- package/dist/tests/explore.test.js +146 -0
- package/dist/tests/explore.test.js.map +1 -0
- package/dist/tests/frontmatter.test.d.ts +2 -0
- package/dist/tests/frontmatter.test.d.ts.map +1 -0
- package/dist/tests/frontmatter.test.js +90 -0
- package/dist/tests/frontmatter.test.js.map +1 -0
- package/dist/tests/fts5.test.d.ts +2 -0
- package/dist/tests/fts5.test.d.ts.map +1 -0
- package/dist/tests/fts5.test.js +95 -0
- package/dist/tests/fts5.test.js.map +1 -0
- package/dist/tests/global-layer.test.d.ts +2 -0
- package/dist/tests/global-layer.test.d.ts.map +1 -0
- package/dist/tests/global-layer.test.js +152 -0
- package/dist/tests/global-layer.test.js.map +1 -0
- package/dist/tests/helpers/db.d.ts +20 -0
- package/dist/tests/helpers/db.d.ts.map +1 -0
- package/dist/tests/helpers/db.js +46 -0
- package/dist/tests/helpers/db.js.map +1 -0
- package/dist/tests/hook-smoke.test.d.ts +2 -0
- package/dist/tests/hook-smoke.test.d.ts.map +1 -0
- package/dist/tests/hook-smoke.test.js +58 -0
- package/dist/tests/hook-smoke.test.js.map +1 -0
- package/dist/tests/init.test.d.ts +2 -0
- package/dist/tests/init.test.d.ts.map +1 -0
- package/dist/tests/init.test.js +109 -0
- package/dist/tests/init.test.js.map +1 -0
- package/dist/tests/log.test.d.ts +2 -0
- package/dist/tests/log.test.d.ts.map +1 -0
- package/dist/tests/log.test.js +68 -0
- package/dist/tests/log.test.js.map +1 -0
- package/dist/tests/post-read.test.d.ts +2 -0
- package/dist/tests/post-read.test.d.ts.map +1 -0
- package/dist/tests/post-read.test.js +69 -0
- package/dist/tests/post-read.test.js.map +1 -0
- package/dist/tests/quality-populate.test.d.ts +2 -0
- package/dist/tests/quality-populate.test.d.ts.map +1 -0
- package/dist/tests/quality-populate.test.js +85 -0
- package/dist/tests/quality-populate.test.js.map +1 -0
- package/dist/tests/read-guard.test.d.ts +2 -0
- package/dist/tests/read-guard.test.d.ts.map +1 -0
- package/dist/tests/read-guard.test.js +69 -0
- package/dist/tests/read-guard.test.js.map +1 -0
- package/dist/tests/reflect.test.d.ts +2 -0
- package/dist/tests/reflect.test.d.ts.map +1 -0
- package/dist/tests/reflect.test.js +122 -0
- package/dist/tests/reflect.test.js.map +1 -0
- package/dist/tests/schemas.test.d.ts +2 -0
- package/dist/tests/schemas.test.d.ts.map +1 -0
- package/dist/tests/schemas.test.js +87 -0
- package/dist/tests/schemas.test.js.map +1 -0
- package/dist/tests/search-hook.test.d.ts +2 -0
- package/dist/tests/search-hook.test.d.ts.map +1 -0
- package/dist/tests/search-hook.test.js +108 -0
- package/dist/tests/search-hook.test.js.map +1 -0
- package/dist/tests/session-focus.test.d.ts +2 -0
- package/dist/tests/session-focus.test.d.ts.map +1 -0
- package/dist/tests/session-focus.test.js +71 -0
- package/dist/tests/session-focus.test.js.map +1 -0
- package/dist/tests/uninstall.test.d.ts +2 -0
- package/dist/tests/uninstall.test.d.ts.map +1 -0
- package/dist/tests/uninstall.test.js +98 -0
- package/dist/tests/uninstall.test.js.map +1 -0
- package/dist/tests/upgrade.test.d.ts +2 -0
- package/dist/tests/upgrade.test.d.ts.map +1 -0
- package/dist/tests/upgrade.test.js +91 -0
- package/dist/tests/upgrade.test.js.map +1 -0
- package/hooks/lib/mindlore-common.cjs +66 -5
- package/hooks/lib/types.d.ts +56 -0
- package/hooks/mindlore-cwd-changed.cjs +57 -0
- package/hooks/mindlore-dont-repeat.cjs +222 -0
- package/hooks/mindlore-fts5-sync.cjs +6 -9
- package/hooks/mindlore-index.cjs +3 -3
- package/hooks/mindlore-post-read.cjs +97 -0
- package/hooks/mindlore-read-guard.cjs +27 -4
- package/hooks/mindlore-search.cjs +73 -52
- package/hooks/mindlore-session-end.cjs +43 -1
- package/hooks/mindlore-session-focus.cjs +14 -0
- package/package.json +21 -8
- package/plugin.json +24 -1
- package/skills/mindlore-decide/SKILL.md +8 -0
- package/skills/mindlore-evolve/SKILL.md +81 -0
- package/skills/mindlore-explore/SKILL.md +84 -0
- package/skills/mindlore-health/SKILL.md +8 -0
- package/skills/mindlore-ingest/SKILL.md +19 -4
- package/skills/mindlore-log/SKILL.md +30 -13
- package/skills/mindlore-query/SKILL.md +8 -0
- package/templates/SCHEMA.md +15 -2
- package/scripts/init.cjs +0 -448
- package/scripts/lib/constants.cjs +0 -49
- package/scripts/mindlore-fts5-index.cjs +0 -112
- package/scripts/mindlore-fts5-search.cjs +0 -119
- package/scripts/mindlore-health-check.cjs +0 -389
- package/scripts/uninstall.cjs +0 -186
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const db_1 = require("./helpers/db");
|
|
9
|
+
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-evolve');
|
|
10
|
+
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
11
|
+
let db;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
(0, db_1.setupTestDir)(TEST_DIR, [
|
|
14
|
+
'raw', 'sources', 'domains', 'analyses', 'insights',
|
|
15
|
+
'connections', 'learnings', 'diary', 'decisions',
|
|
16
|
+
]);
|
|
17
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_DIR, 'INDEX.md'), [
|
|
18
|
+
'# Knowledge Index',
|
|
19
|
+
'',
|
|
20
|
+
'## Sources',
|
|
21
|
+
'- [react-hooks](sources/react-hooks.md)',
|
|
22
|
+
'- [cc-internals](sources/cc-internals.md)',
|
|
23
|
+
'',
|
|
24
|
+
'## Domains',
|
|
25
|
+
'- [frontend](domains/frontend.md)',
|
|
26
|
+
].join('\n'));
|
|
27
|
+
db = (0, db_1.createTestDb)(DB_PATH);
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
db.close();
|
|
31
|
+
(0, db_1.teardownTestDir)(TEST_DIR);
|
|
32
|
+
});
|
|
33
|
+
describe('Evolve — orphan detection and cross-reference analysis', () => {
|
|
34
|
+
test('detects orphan files not listed in INDEX.md', () => {
|
|
35
|
+
// Create a source file that IS in INDEX
|
|
36
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_DIR, 'sources', 'react-hooks.md'), '---\nslug: react-hooks\ntype: source\n---\n# React Hooks\n');
|
|
37
|
+
// Create a source file NOT in INDEX (orphan)
|
|
38
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_DIR, 'sources', 'orphan-doc.md'), '---\nslug: orphan-doc\ntype: source\n---\n# Orphan\n');
|
|
39
|
+
const indexContent = fs_1.default.readFileSync(path_1.default.join(TEST_DIR, 'INDEX.md'), 'utf8');
|
|
40
|
+
const sourceFiles = fs_1.default.readdirSync(path_1.default.join(TEST_DIR, 'sources'))
|
|
41
|
+
.filter(f => f.endsWith('.md'));
|
|
42
|
+
const orphans = sourceFiles.filter(f => !indexContent.includes(f.replace('.md', '')));
|
|
43
|
+
expect(orphans).toContain('orphan-doc.md');
|
|
44
|
+
expect(orphans).not.toContain('react-hooks.md');
|
|
45
|
+
});
|
|
46
|
+
test('detects source without domain reference', () => {
|
|
47
|
+
// Source exists
|
|
48
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_DIR, 'sources', 'cc-internals.md'), '---\nslug: cc-internals\ntype: source\n---\n# CC Internals\nHooks and memory.\n');
|
|
49
|
+
// Domain exists but doesn't reference cc-internals
|
|
50
|
+
fs_1.default.writeFileSync(path_1.default.join(TEST_DIR, 'domains', 'frontend.md'), '---\nslug: frontend\ntype: domain\n---\n# Frontend\nReact and Vue patterns.\n');
|
|
51
|
+
const domainContent = fs_1.default.readFileSync(path_1.default.join(TEST_DIR, 'domains', 'frontend.md'), 'utf8');
|
|
52
|
+
const sourceFiles = fs_1.default.readdirSync(path_1.default.join(TEST_DIR, 'sources'))
|
|
53
|
+
.filter(f => f.endsWith('.md'));
|
|
54
|
+
const unreferenced = sourceFiles.filter(f => {
|
|
55
|
+
const slug = f.replace('.md', '');
|
|
56
|
+
return !domainContent.includes(slug);
|
|
57
|
+
});
|
|
58
|
+
expect(unreferenced).toContain('cc-internals.md');
|
|
59
|
+
});
|
|
60
|
+
test('INDEX.md can be updated with new entries', () => {
|
|
61
|
+
const indexPath = path_1.default.join(TEST_DIR, 'INDEX.md');
|
|
62
|
+
const original = fs_1.default.readFileSync(indexPath, 'utf8');
|
|
63
|
+
// Add new source reference
|
|
64
|
+
const updated = original.replace('## Domains', '- [new-source](sources/new-source.md)\n\n## Domains');
|
|
65
|
+
fs_1.default.writeFileSync(indexPath, updated);
|
|
66
|
+
const content = fs_1.default.readFileSync(indexPath, 'utf8');
|
|
67
|
+
expect(content).toContain('new-source');
|
|
68
|
+
expect(content).toContain('react-hooks');
|
|
69
|
+
});
|
|
70
|
+
test('log.md receives EVOLVE entries', () => {
|
|
71
|
+
const logPath = path_1.default.join(TEST_DIR, 'log.md');
|
|
72
|
+
fs_1.default.writeFileSync(logPath, '| Date | Op | File |\n|------|-----|------|\n');
|
|
73
|
+
const entry = `| 2026-04-12 | evolve | 2 orphans fixed, 1 ref added |\n`;
|
|
74
|
+
fs_1.default.appendFileSync(logPath, entry);
|
|
75
|
+
const content = fs_1.default.readFileSync(logPath, 'utf8');
|
|
76
|
+
expect(content).toContain('evolve');
|
|
77
|
+
expect(content).toContain('orphans fixed');
|
|
78
|
+
});
|
|
79
|
+
test('FTS5 indexed sources can be queried for staleness check', () => {
|
|
80
|
+
(0, db_1.insertFts)(db, {
|
|
81
|
+
path: path_1.default.join(TEST_DIR, 'sources', 'react-hooks.md'),
|
|
82
|
+
slug: 'react-hooks',
|
|
83
|
+
type: 'source',
|
|
84
|
+
title: 'React Hooks',
|
|
85
|
+
content: 'React hooks patterns',
|
|
86
|
+
dateCaptured: '2026-03-01',
|
|
87
|
+
});
|
|
88
|
+
(0, db_1.insertFts)(db, {
|
|
89
|
+
path: path_1.default.join(TEST_DIR, 'domains', 'frontend.md'),
|
|
90
|
+
slug: 'frontend',
|
|
91
|
+
type: 'domain',
|
|
92
|
+
title: 'Frontend',
|
|
93
|
+
content: 'Frontend development patterns',
|
|
94
|
+
dateCaptured: '2026-01-15',
|
|
95
|
+
});
|
|
96
|
+
// Domain is older than source — potentially stale
|
|
97
|
+
const sources = db.prepare("SELECT slug, date_captured FROM mindlore_fts WHERE type = 'source'").all();
|
|
98
|
+
const domains = db.prepare("SELECT slug, date_captured FROM mindlore_fts WHERE type = 'domain'").all();
|
|
99
|
+
expect(sources[0].date_captured).toBe('2026-03-01');
|
|
100
|
+
expect(domains[0].date_captured).toBe('2026-01-15');
|
|
101
|
+
// Domain is older → candidate for evolve update
|
|
102
|
+
expect(domains[0].date_captured < sources[0].date_captured).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=evolve.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evolve.test.js","sourceRoot":"","sources":["../../tests/evolve.test.ts"],"names":[],"mappings":";;;;;AAAA,4CAAoB;AACpB,gDAAwB;AAExB,qCAAsF;AAEtF,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AAC5D,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEnD,IAAI,EAAqB,CAAC;AAE1B,UAAU,CAAC,GAAG,EAAE;IACd,IAAA,iBAAY,EAAC,QAAQ,EAAE;QACrB,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;QACnD,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW;KACjD,CAAC,CAAC;IACH,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE;QAChD,mBAAmB;QACnB,EAAE;QACF,YAAY;QACZ,yCAAyC;QACzC,2CAA2C;QAC3C,EAAE;QACF,YAAY;QACZ,mCAAmC;KACpC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEd,EAAE,GAAG,IAAA,iBAAY,EAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,IAAA,oBAAe,EAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wDAAwD,EAAE,GAAG,EAAE;IACtE,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACvD,wCAAwC;QACxC,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,CAAC,EAC/D,4DAA4D,CAAC,CAAC;QAEhE,6CAA6C;QAC7C,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,eAAe,CAAC,EAC9D,sDAAsD,CAAC,CAAC;QAE1D,MAAM,YAAY,GAAG,YAAE,CAAC,YAAY,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9E,MAAM,WAAW,GAAG,YAAE,CAAC,WAAW,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;aAC/D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAElC,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACtF,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC3C,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACnD,gBAAgB;QAChB,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,iBAAiB,CAAC,EAChE,iFAAiF,CAAC,CAAC;QAErF,mDAAmD;QACnD,YAAE,CAAC,aAAa,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,EAC5D,+EAA+E,CAAC,CAAC;QAEnF,MAAM,aAAa,GAAG,YAAE,CAAC,YAAY,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7F,MAAM,WAAW,GAAG,YAAE,CAAC,WAAW,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;aAC/D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAElC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAEpD,2BAA2B;QAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAC9B,YAAY,EACZ,qDAAqD,CACtD,CAAC;QACF,YAAE,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9C,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,+CAA+C,CAAC,CAAC;QAE3E,MAAM,KAAK,GAAG,0DAA0D,CAAC;QACzE,YAAE,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAElC,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACnE,IAAA,cAAS,EAAC,EAAE,EAAE;YACZ,IAAI,EAAE,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,CAAC;YACtD,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,sBAAsB;YAC/B,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;QAEH,IAAA,cAAS,EAAC,EAAE,EAAE;YACZ,IAAI,EAAE,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC;YACnD,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,+BAA+B;YACxC,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;QAEH,kDAAkD;QAClD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CACxB,oEAAoE,CACrE,CAAC,GAAG,EAA2D,CAAC;QAEjE,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CACxB,oEAAoE,CACrE,CAAC,GAAG,EAA2D,CAAC;QAEjE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,gDAAgD;QAChD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,aAAc,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC,aAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.test.d.ts","sourceRoot":"","sources":["../../tests/explore.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const db_1 = require("./helpers/db");
|
|
9
|
+
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-explore');
|
|
10
|
+
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
11
|
+
let db;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
(0, db_1.setupTestDir)(TEST_DIR, ['sources', 'domains', 'connections']);
|
|
14
|
+
db = (0, db_1.createTestDb)(DB_PATH);
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
db.close();
|
|
18
|
+
(0, db_1.teardownTestDir)(TEST_DIR);
|
|
19
|
+
});
|
|
20
|
+
describe('Explore — cross-reference detection and connections', () => {
|
|
21
|
+
test('detects shared tags between sources', () => {
|
|
22
|
+
(0, db_1.insertFts)(db, {
|
|
23
|
+
path: path_1.default.join(TEST_DIR, 'sources', 'react-hooks.md'),
|
|
24
|
+
slug: 'react-hooks',
|
|
25
|
+
type: 'source',
|
|
26
|
+
content: 'React hooks for state management',
|
|
27
|
+
tags: 'hooks, react, state',
|
|
28
|
+
});
|
|
29
|
+
(0, db_1.insertFts)(db, {
|
|
30
|
+
path: path_1.default.join(TEST_DIR, 'sources', 'vue-composables.md'),
|
|
31
|
+
slug: 'vue-composables',
|
|
32
|
+
type: 'source',
|
|
33
|
+
content: 'Vue composables for state management',
|
|
34
|
+
tags: 'hooks, vue, state',
|
|
35
|
+
});
|
|
36
|
+
(0, db_1.insertFts)(db, {
|
|
37
|
+
path: path_1.default.join(TEST_DIR, 'sources', 'python-ml.md'),
|
|
38
|
+
slug: 'python-ml',
|
|
39
|
+
type: 'source',
|
|
40
|
+
content: 'Machine learning with Python',
|
|
41
|
+
tags: 'python, ml',
|
|
42
|
+
});
|
|
43
|
+
// Find tag overlaps
|
|
44
|
+
const allSources = db.prepare("SELECT slug, tags FROM mindlore_fts WHERE type = 'source'").all();
|
|
45
|
+
const tagMap = {};
|
|
46
|
+
for (const src of allSources) {
|
|
47
|
+
if (!src.tags)
|
|
48
|
+
continue;
|
|
49
|
+
for (const tag of src.tags.split(',').map(t => t.trim())) {
|
|
50
|
+
if (!tagMap[tag])
|
|
51
|
+
tagMap[tag] = [];
|
|
52
|
+
tagMap[tag].push(src.slug);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// "hooks" and "state" shared by react-hooks + vue-composables
|
|
56
|
+
expect(tagMap['hooks']).toHaveLength(2);
|
|
57
|
+
expect(tagMap['state']).toHaveLength(2);
|
|
58
|
+
// "python" only in python-ml
|
|
59
|
+
expect(tagMap['python']).toHaveLength(1);
|
|
60
|
+
});
|
|
61
|
+
test('connections file has correct frontmatter format', () => {
|
|
62
|
+
const connectionContent = [
|
|
63
|
+
'---',
|
|
64
|
+
'type: connection',
|
|
65
|
+
'slug: conn-react-vue-state',
|
|
66
|
+
'date_created: 2026-04-12',
|
|
67
|
+
'sources: [react-hooks.md, vue-composables.md]',
|
|
68
|
+
'strength: high',
|
|
69
|
+
'tags: hooks, state',
|
|
70
|
+
'---',
|
|
71
|
+
'',
|
|
72
|
+
'## Connection',
|
|
73
|
+
'Both sources discuss hooks-based state management in different frameworks.',
|
|
74
|
+
'',
|
|
75
|
+
'## Action Suggestion',
|
|
76
|
+
'Create a cross-framework state management domain page.',
|
|
77
|
+
].join('\n');
|
|
78
|
+
const connPath = path_1.default.join(TEST_DIR, 'connections', 'conn-react-vue-state.md');
|
|
79
|
+
fs_1.default.writeFileSync(connPath, connectionContent);
|
|
80
|
+
const content = fs_1.default.readFileSync(connPath, 'utf8');
|
|
81
|
+
expect(content).toContain('type: connection');
|
|
82
|
+
expect(content).toContain('strength: high');
|
|
83
|
+
expect(content).toContain('sources: [react-hooks.md, vue-composables.md]');
|
|
84
|
+
expect(content).toContain('## Connection');
|
|
85
|
+
expect(content).toContain('## Action Suggestion');
|
|
86
|
+
});
|
|
87
|
+
test('duplicate connections are not created for same source pair', () => {
|
|
88
|
+
const connectionsDir = path_1.default.join(TEST_DIR, 'connections');
|
|
89
|
+
// Existing connection for source-a + source-b
|
|
90
|
+
fs_1.default.writeFileSync(path_1.default.join(connectionsDir, 'conn-a-b.md'), '---\ntype: connection\nslug: conn-a-b\nsources: [source-a.md, source-b.md]\n---\n');
|
|
91
|
+
expect(fs_1.default.readdirSync(connectionsDir).filter(f => f.endsWith('.md'))).toHaveLength(1);
|
|
92
|
+
// Simulate duplicate check before writing
|
|
93
|
+
const newPair = ['source-a.md', 'source-b.md'];
|
|
94
|
+
const newPairKey = newPair.sort().join('+');
|
|
95
|
+
const existingFiles = fs_1.default.readdirSync(connectionsDir).filter(f => f.endsWith('.md'));
|
|
96
|
+
const alreadyExists = existingFiles.some(f => {
|
|
97
|
+
const content = fs_1.default.readFileSync(path_1.default.join(connectionsDir, f), 'utf8');
|
|
98
|
+
const match = content.match(/sources:\s*\[([^\]]+)\]/);
|
|
99
|
+
if (!match)
|
|
100
|
+
return false;
|
|
101
|
+
return match[1].split(',').map(s => s.trim()).sort().join('+') === newPairKey;
|
|
102
|
+
});
|
|
103
|
+
// Should detect existing pair
|
|
104
|
+
expect(alreadyExists).toBe(true);
|
|
105
|
+
// Only write if NOT already exists
|
|
106
|
+
if (!alreadyExists) {
|
|
107
|
+
fs_1.default.writeFileSync(path_1.default.join(connectionsDir, 'conn-a-b-2.md'), 'duplicate');
|
|
108
|
+
}
|
|
109
|
+
// File count should still be 1 — no duplicate written
|
|
110
|
+
expect(fs_1.default.readdirSync(connectionsDir).filter(f => f.endsWith('.md'))).toHaveLength(1);
|
|
111
|
+
});
|
|
112
|
+
test('connections are indexable in FTS5', () => {
|
|
113
|
+
(0, db_1.insertFts)(db, {
|
|
114
|
+
path: path_1.default.join(TEST_DIR, 'connections', 'conn-test.md'),
|
|
115
|
+
slug: 'conn-test',
|
|
116
|
+
type: 'connection',
|
|
117
|
+
title: 'Test Connection',
|
|
118
|
+
content: 'Two sources share hooks patterns',
|
|
119
|
+
tags: 'hooks',
|
|
120
|
+
});
|
|
121
|
+
const results = db.prepare("SELECT slug FROM mindlore_fts WHERE type = 'connection'").all();
|
|
122
|
+
expect(results).toHaveLength(1);
|
|
123
|
+
expect(results[0].slug).toBe('conn-test');
|
|
124
|
+
// Searchable by content
|
|
125
|
+
const searchResults = db.prepare("SELECT slug FROM mindlore_fts WHERE mindlore_fts MATCH 'hooks' AND type = 'connection'").all();
|
|
126
|
+
expect(searchResults).toHaveLength(1);
|
|
127
|
+
});
|
|
128
|
+
test('strength ranking: high requires 3+ shared tags', () => {
|
|
129
|
+
// Simulate strength calculation
|
|
130
|
+
const tagsA = ['hooks', 'state', 'reactivity', 'frontend'].map(t => t.trim());
|
|
131
|
+
const tagsB = ['hooks', 'state', 'reactivity', 'vue'].map(t => t.trim());
|
|
132
|
+
const shared = tagsA.filter(t => tagsB.includes(t));
|
|
133
|
+
const strength = shared.length >= 3 ? 'high' : shared.length >= 2 ? 'medium' : 'low';
|
|
134
|
+
expect(shared).toHaveLength(3);
|
|
135
|
+
expect(strength).toBe('high');
|
|
136
|
+
});
|
|
137
|
+
test('log.md receives EXPLORE entries', () => {
|
|
138
|
+
const logPath = path_1.default.join(TEST_DIR, 'log.md');
|
|
139
|
+
fs_1.default.writeFileSync(logPath, '| Date | Op | File |\n|------|-----|------|\n');
|
|
140
|
+
fs_1.default.appendFileSync(logPath, '| 2026-04-12 | explore | 2 connections found |\n');
|
|
141
|
+
const content = fs_1.default.readFileSync(logPath, 'utf8');
|
|
142
|
+
expect(content).toContain('explore');
|
|
143
|
+
expect(content).toContain('connections found');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=explore.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.test.js","sourceRoot":"","sources":["../../tests/explore.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.test.d.ts","sourceRoot":"","sources":["../../tests/frontmatter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const constants_js_1 = require("../scripts/lib/constants.js");
|
|
4
|
+
const { parseFrontmatter: parse, extractFtsMetadata } = require('../hooks/lib/mindlore-common.cjs');
|
|
5
|
+
describe('Frontmatter Parser', () => {
|
|
6
|
+
function parseFrontmatter(content) {
|
|
7
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
8
|
+
if (!match?.[1])
|
|
9
|
+
return null;
|
|
10
|
+
const fm = {};
|
|
11
|
+
const lines = match[1].split('\n');
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const colonIdx = line.indexOf(':');
|
|
14
|
+
if (colonIdx === -1)
|
|
15
|
+
continue;
|
|
16
|
+
const key = line.slice(0, colonIdx).trim();
|
|
17
|
+
const rawValue = line.slice(colonIdx + 1).trim();
|
|
18
|
+
if (rawValue.startsWith('[') && rawValue.endsWith(']')) {
|
|
19
|
+
fm[key] = rawValue
|
|
20
|
+
.slice(1, -1)
|
|
21
|
+
.split(',')
|
|
22
|
+
.map((s) => s.trim());
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
fm[key] = rawValue;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return Object.keys(fm).length > 0 ? fm : null;
|
|
29
|
+
}
|
|
30
|
+
test('should parse valid frontmatter', () => {
|
|
31
|
+
const content = [
|
|
32
|
+
'---',
|
|
33
|
+
'slug: my-source',
|
|
34
|
+
'type: source',
|
|
35
|
+
'title: My Source',
|
|
36
|
+
'tags: [typescript, node]',
|
|
37
|
+
'---',
|
|
38
|
+
'',
|
|
39
|
+
'# My Source',
|
|
40
|
+
].join('\n');
|
|
41
|
+
const fm = parseFrontmatter(content);
|
|
42
|
+
expect(fm).not.toBeNull();
|
|
43
|
+
expect(fm.slug).toBe('my-source');
|
|
44
|
+
expect(fm.type).toBe('source');
|
|
45
|
+
expect(fm.title).toBe('My Source');
|
|
46
|
+
expect(fm.tags).toEqual(['typescript', 'node']);
|
|
47
|
+
});
|
|
48
|
+
test('should return null for missing frontmatter', () => {
|
|
49
|
+
const content = '# No Frontmatter\n\nJust content.';
|
|
50
|
+
const fm = parseFrontmatter(content);
|
|
51
|
+
expect(fm).toBeNull();
|
|
52
|
+
});
|
|
53
|
+
test('should handle empty frontmatter', () => {
|
|
54
|
+
const content = '---\n---\n# Empty';
|
|
55
|
+
const fm = parseFrontmatter(content);
|
|
56
|
+
expect(fm).toBeNull();
|
|
57
|
+
});
|
|
58
|
+
test('should handle frontmatter with single field', () => {
|
|
59
|
+
const content = '---\nslug: minimal\n---\n# Minimal';
|
|
60
|
+
const fm = parseFrontmatter(content);
|
|
61
|
+
expect(fm).not.toBeNull();
|
|
62
|
+
expect(fm.slug).toBe('minimal');
|
|
63
|
+
});
|
|
64
|
+
test('should handle CRLF line endings', () => {
|
|
65
|
+
const content = '---\r\nslug: test\r\ntype: raw\r\n---\r\n# Test';
|
|
66
|
+
const fm = parseFrontmatter(content);
|
|
67
|
+
expect(fm).not.toBeNull();
|
|
68
|
+
expect(fm.slug).toBe('test');
|
|
69
|
+
expect(fm.type).toBe('raw');
|
|
70
|
+
});
|
|
71
|
+
test('should validate type-directory mapping', () => {
|
|
72
|
+
expect(Object.keys(constants_js_1.TYPE_TO_DIR)).toHaveLength(9);
|
|
73
|
+
const dirs = new Set(Object.values(constants_js_1.TYPE_TO_DIR));
|
|
74
|
+
expect(dirs.size).toBe(9);
|
|
75
|
+
});
|
|
76
|
+
test('should extract tags for FTS5 indexing', () => {
|
|
77
|
+
const content = '---\nslug: tagged\ntype: source\ntags: [security, hooks, fts5]\n---\n# Tagged Doc\n\nContent.';
|
|
78
|
+
const { meta, body } = parse(content);
|
|
79
|
+
const result = extractFtsMetadata(meta, body, '/test/sources/tagged.md', '/test');
|
|
80
|
+
expect(result.tags).toBe('security, hooks, fts5');
|
|
81
|
+
expect(result.quality).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
test('should handle values containing colons', () => {
|
|
84
|
+
const content = '---\nsource_url: https://example.com/path\nslug: test\n---\n';
|
|
85
|
+
const fm = parseFrontmatter(content);
|
|
86
|
+
expect(fm).not.toBeNull();
|
|
87
|
+
expect(fm.source_url).toBe('https://example.com/path');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=frontmatter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.test.js","sourceRoot":"","sources":["../../tests/frontmatter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fts5.test.d.ts","sourceRoot":"","sources":["../../tests/fts5.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
8
|
+
const db_js_1 = require("./helpers/db.js");
|
|
9
|
+
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-mindlore-fts5');
|
|
10
|
+
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
|
|
13
|
+
const db = (0, db_js_1.createTestDb)(DB_PATH);
|
|
14
|
+
db.close();
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
18
|
+
});
|
|
19
|
+
describe('FTS5 Database', () => {
|
|
20
|
+
test('should create FTS5 table and insert content', () => {
|
|
21
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
22
|
+
const testContent = '# Test Source\n\nThis is about TypeScript and Node.js performance.';
|
|
23
|
+
const testPath = path_1.default.join(TEST_DIR, 'sources', 'test-source.md');
|
|
24
|
+
(0, db_js_1.insertFts)(db, { path: testPath, slug: 'test-source', description: 'TypeScript and Node.js performance', type: 'source', category: 'sources', title: 'Test Source', content: testContent, tags: '', quality: null });
|
|
25
|
+
const result = db.prepare('SELECT count(*) as cnt FROM mindlore_fts').get();
|
|
26
|
+
expect(result.cnt).toBe(1);
|
|
27
|
+
db.close();
|
|
28
|
+
});
|
|
29
|
+
test('should find content via FTS5 MATCH query', () => {
|
|
30
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
31
|
+
const testPath = path_1.default.join(TEST_DIR, 'sources', 'typescript-guide.md');
|
|
32
|
+
const content = '# TypeScript Guide\n\nTypeScript provides static typing for JavaScript applications.';
|
|
33
|
+
(0, db_js_1.insertFts)(db, { path: testPath, slug: 'typescript-guide', description: 'TypeScript static typing for JavaScript', type: 'source', category: 'sources', title: 'TypeScript Guide', content, tags: '', quality: null });
|
|
34
|
+
const results = db
|
|
35
|
+
.prepare(`SELECT path, rank FROM mindlore_fts
|
|
36
|
+
WHERE mindlore_fts MATCH ?
|
|
37
|
+
ORDER BY rank
|
|
38
|
+
LIMIT 3`)
|
|
39
|
+
.all('TypeScript');
|
|
40
|
+
expect(results).toHaveLength(1);
|
|
41
|
+
expect(results[0].path).toBe(testPath);
|
|
42
|
+
db.close();
|
|
43
|
+
});
|
|
44
|
+
test('should return empty results for non-matching query', () => {
|
|
45
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
46
|
+
const testPath = path_1.default.join(TEST_DIR, 'sources', 'python-guide.md');
|
|
47
|
+
(0, db_js_1.insertFts)(db, { path: testPath, slug: 'python-guide', description: 'Python for data science', type: 'source', category: 'sources', title: 'Python Guide', content: '# Python Guide\n\nPython is great for data science.', tags: '', quality: null });
|
|
48
|
+
const results = db
|
|
49
|
+
.prepare(`SELECT path FROM mindlore_fts
|
|
50
|
+
WHERE mindlore_fts MATCH ?
|
|
51
|
+
ORDER BY rank
|
|
52
|
+
LIMIT 3`)
|
|
53
|
+
.all('Kubernetes');
|
|
54
|
+
expect(results).toHaveLength(0);
|
|
55
|
+
db.close();
|
|
56
|
+
});
|
|
57
|
+
test('should rank results by BM25 relevance', () => {
|
|
58
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
59
|
+
(0, db_js_1.insertFts)(db, { path: path_1.default.join(TEST_DIR, 'sources', 'hooks-overview.md'), slug: 'hooks-overview', description: 'Hooks lifecycle callbacks overview', type: 'source', category: 'sources', title: 'Hooks Overview', content: '# Hooks Overview\n\nHooks are lifecycle callbacks.', tags: '', quality: null });
|
|
60
|
+
(0, db_js_1.insertFts)(db, { path: path_1.default.join(TEST_DIR, 'sources', 'hooks-deep-dive.md'), slug: 'hooks-deep-dive', description: 'Deep dive into hooks patterns', type: 'source', category: 'sources', title: 'Hooks Deep Dive', content: '# Hooks Deep Dive\n\nHooks hooks hooks. PreToolUse hooks, PostToolUse hooks, SessionStart hooks.', tags: '', quality: null });
|
|
61
|
+
const results = db
|
|
62
|
+
.prepare(`SELECT path, rank FROM mindlore_fts
|
|
63
|
+
WHERE mindlore_fts MATCH ?
|
|
64
|
+
ORDER BY rank
|
|
65
|
+
LIMIT 3`)
|
|
66
|
+
.all('hooks');
|
|
67
|
+
expect(results).toHaveLength(2);
|
|
68
|
+
const deepDive = results.find((r) => r.path.includes('deep-dive'));
|
|
69
|
+
const overview = results.find((r) => r.path.includes('overview'));
|
|
70
|
+
expect(deepDive).toBeDefined();
|
|
71
|
+
expect(overview).toBeDefined();
|
|
72
|
+
db.close();
|
|
73
|
+
});
|
|
74
|
+
test('should index and search by tags column', () => {
|
|
75
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
76
|
+
(0, db_js_1.insertFts)(db, { path: path_1.default.join(TEST_DIR, 'sources', 'tagged-doc.md'), slug: 'tagged-doc', description: 'A doc with tags', type: 'source', category: 'sources', title: 'Tagged Doc', content: '# Tagged\n\nContent here.', tags: 'security, hooks, fts5', quality: null });
|
|
77
|
+
const results = db
|
|
78
|
+
.prepare(`SELECT path, tags FROM mindlore_fts
|
|
79
|
+
WHERE tags MATCH ?
|
|
80
|
+
ORDER BY rank
|
|
81
|
+
LIMIT 3`)
|
|
82
|
+
.all('security');
|
|
83
|
+
expect(results).toHaveLength(1);
|
|
84
|
+
expect(results[0].tags).toBe('security, hooks, fts5');
|
|
85
|
+
db.close();
|
|
86
|
+
});
|
|
87
|
+
test('should accept null quality column', () => {
|
|
88
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
89
|
+
(0, db_js_1.insertFts)(db, { path: path_1.default.join(TEST_DIR, 'sources', 'no-quality.md'), slug: 'no-quality', description: 'No quality set', type: 'source', category: 'sources', title: 'No Quality', content: '# Test\n\nContent.', tags: '', quality: null });
|
|
90
|
+
const result = db.prepare('SELECT quality FROM mindlore_fts WHERE path = ?').get(path_1.default.join(TEST_DIR, 'sources', 'no-quality.md'));
|
|
91
|
+
expect(result.quality).toBeFalsy();
|
|
92
|
+
db.close();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=fts5.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fts5.test.js","sourceRoot":"","sources":["../../tests/fts5.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-layer.test.d.ts","sourceRoot":"","sources":["../../tests/global-layer.test.ts"],"names":[],"mappings":""}
|