mindlore 0.4.3 → 0.5.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 (120) hide show
  1. package/README.md +2 -1
  2. package/dist/scripts/init.js +45 -3
  3. package/dist/scripts/init.js.map +1 -1
  4. package/dist/scripts/lib/constants.d.ts +15 -0
  5. package/dist/scripts/lib/constants.d.ts.map +1 -1
  6. package/dist/scripts/lib/constants.js +16 -1
  7. package/dist/scripts/lib/constants.js.map +1 -1
  8. package/dist/scripts/lib/db-helpers.d.ts +15 -0
  9. package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
  10. package/dist/scripts/lib/db-helpers.js +51 -0
  11. package/dist/scripts/lib/db-helpers.js.map +1 -1
  12. package/dist/scripts/lib/embedding.d.ts +5 -0
  13. package/dist/scripts/lib/embedding.d.ts.map +1 -0
  14. package/dist/scripts/lib/embedding.js +44 -0
  15. package/dist/scripts/lib/embedding.js.map +1 -0
  16. package/dist/scripts/lib/hybrid-search.d.ts +62 -0
  17. package/dist/scripts/lib/hybrid-search.d.ts.map +1 -0
  18. package/dist/scripts/lib/hybrid-search.js +150 -0
  19. package/dist/scripts/lib/hybrid-search.js.map +1 -0
  20. package/dist/scripts/lib/migrations-v051.d.ts +3 -0
  21. package/dist/scripts/lib/migrations-v051.d.ts.map +1 -0
  22. package/dist/scripts/lib/migrations-v051.js +24 -0
  23. package/dist/scripts/lib/migrations-v051.js.map +1 -0
  24. package/dist/scripts/lib/migrations.d.ts +4 -0
  25. package/dist/scripts/lib/migrations.d.ts.map +1 -0
  26. package/dist/scripts/lib/migrations.js +40 -0
  27. package/dist/scripts/lib/migrations.js.map +1 -0
  28. package/dist/scripts/lib/privacy-filter.d.ts +3 -0
  29. package/dist/scripts/lib/privacy-filter.d.ts.map +1 -0
  30. package/dist/scripts/lib/privacy-filter.js +28 -0
  31. package/dist/scripts/lib/privacy-filter.js.map +1 -0
  32. package/dist/scripts/lib/schema-version.d.ts +13 -0
  33. package/dist/scripts/lib/schema-version.d.ts.map +1 -0
  34. package/dist/scripts/lib/schema-version.js +37 -0
  35. package/dist/scripts/lib/schema-version.js.map +1 -0
  36. package/dist/scripts/lib/similarity.d.ts +12 -0
  37. package/dist/scripts/lib/similarity.d.ts.map +1 -0
  38. package/dist/scripts/lib/similarity.js +64 -0
  39. package/dist/scripts/lib/similarity.js.map +1 -0
  40. package/dist/scripts/lib/synonym.d.ts +4 -0
  41. package/dist/scripts/lib/synonym.d.ts.map +1 -0
  42. package/dist/scripts/lib/synonym.js +37 -0
  43. package/dist/scripts/lib/synonym.js.map +1 -0
  44. package/dist/scripts/mindlore-fts5-index.d.ts +2 -1
  45. package/dist/scripts/mindlore-fts5-index.d.ts.map +1 -1
  46. package/dist/scripts/mindlore-fts5-index.js +71 -5
  47. package/dist/scripts/mindlore-fts5-index.js.map +1 -1
  48. package/dist/scripts/mindlore-fts5-search.d.ts +3 -2
  49. package/dist/scripts/mindlore-fts5-search.d.ts.map +1 -1
  50. package/dist/scripts/mindlore-fts5-search.js +89 -35
  51. package/dist/scripts/mindlore-fts5-search.js.map +1 -1
  52. package/dist/scripts/mindlore-health-check.js +105 -0
  53. package/dist/scripts/mindlore-health-check.js.map +1 -1
  54. package/dist/scripts/quality-populate.js +8 -4
  55. package/dist/scripts/quality-populate.js.map +1 -1
  56. package/dist/tests/cc-memory-sync.test.d.ts +2 -0
  57. package/dist/tests/cc-memory-sync.test.d.ts.map +1 -0
  58. package/dist/tests/cc-memory-sync.test.js +121 -0
  59. package/dist/tests/cc-memory-sync.test.js.map +1 -0
  60. package/dist/tests/embedding.test.d.ts +6 -0
  61. package/dist/tests/embedding.test.d.ts.map +1 -0
  62. package/dist/tests/embedding.test.js +71 -0
  63. package/dist/tests/embedding.test.js.map +1 -0
  64. package/dist/tests/episode-file.test.d.ts +2 -0
  65. package/dist/tests/episode-file.test.d.ts.map +1 -0
  66. package/dist/tests/episode-file.test.js +79 -0
  67. package/dist/tests/episode-file.test.js.map +1 -0
  68. package/dist/tests/fts5.test.js +82 -0
  69. package/dist/tests/fts5.test.js.map +1 -1
  70. package/dist/tests/helpers/db.d.ts +6 -0
  71. package/dist/tests/helpers/db.d.ts.map +1 -1
  72. package/dist/tests/helpers/db.js +29 -0
  73. package/dist/tests/helpers/db.js.map +1 -1
  74. package/dist/tests/hook-logging.test.d.ts +2 -0
  75. package/dist/tests/hook-logging.test.d.ts.map +1 -0
  76. package/dist/tests/hook-logging.test.js +108 -0
  77. package/dist/tests/hook-logging.test.js.map +1 -0
  78. package/dist/tests/hybrid-search.test.d.ts +2 -0
  79. package/dist/tests/hybrid-search.test.d.ts.map +1 -0
  80. package/dist/tests/hybrid-search.test.js +114 -0
  81. package/dist/tests/hybrid-search.test.js.map +1 -0
  82. package/dist/tests/index-cli-embed.test.d.ts +7 -0
  83. package/dist/tests/index-cli-embed.test.d.ts.map +1 -0
  84. package/dist/tests/index-cli-embed.test.js +128 -0
  85. package/dist/tests/index-cli-embed.test.js.map +1 -0
  86. package/dist/tests/privacy-filter.test.d.ts +2 -0
  87. package/dist/tests/privacy-filter.test.d.ts.map +1 -0
  88. package/dist/tests/privacy-filter.test.js +56 -0
  89. package/dist/tests/privacy-filter.test.js.map +1 -0
  90. package/dist/tests/schema-version.test.d.ts +2 -0
  91. package/dist/tests/schema-version.test.d.ts.map +1 -0
  92. package/dist/tests/schema-version.test.js +127 -0
  93. package/dist/tests/schema-version.test.js.map +1 -0
  94. package/dist/tests/search-cli-hybrid.test.d.ts +6 -0
  95. package/dist/tests/search-cli-hybrid.test.d.ts.map +1 -0
  96. package/dist/tests/search-cli-hybrid.test.js +103 -0
  97. package/dist/tests/search-cli-hybrid.test.js.map +1 -0
  98. package/dist/tests/search-hook.test.js +44 -0
  99. package/dist/tests/search-hook.test.js.map +1 -1
  100. package/dist/tests/similarity.test.d.ts +2 -0
  101. package/dist/tests/similarity.test.d.ts.map +1 -0
  102. package/dist/tests/similarity.test.js +61 -0
  103. package/dist/tests/similarity.test.js.map +1 -0
  104. package/dist/tests/synonym.test.d.ts +2 -0
  105. package/dist/tests/synonym.test.d.ts.map +1 -0
  106. package/dist/tests/synonym.test.js +47 -0
  107. package/dist/tests/synonym.test.js.map +1 -0
  108. package/dist/tests/token-budget.test.d.ts +2 -0
  109. package/dist/tests/token-budget.test.d.ts.map +1 -0
  110. package/dist/tests/token-budget.test.js +32 -0
  111. package/dist/tests/token-budget.test.js.map +1 -0
  112. package/hooks/lib/mindlore-common.cjs +120 -0
  113. package/hooks/mindlore-index.cjs +82 -2
  114. package/hooks/mindlore-search.cjs +102 -35
  115. package/hooks/mindlore-session-end.cjs +129 -39
  116. package/hooks/mindlore-session-focus.cjs +24 -3
  117. package/package.json +6 -4
  118. package/plugin.json +1 -1
  119. package/skills/mindlore-ingest/SKILL.md +7 -1
  120. package/templates/config.json +20 -1
@@ -0,0 +1,108 @@
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 os_1 = __importDefault(require("os"));
9
+ const { hookLog, getRecentHookErrors } = require('../hooks/lib/mindlore-common.cjs');
10
+ let tmpDir;
11
+ let origEnv;
12
+ beforeEach(() => {
13
+ tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'mindlore-hooklog-'));
14
+ fs_1.default.mkdirSync(path_1.default.join(tmpDir, 'diary'), { recursive: true });
15
+ origEnv = process.env.MINDLORE_HOME;
16
+ process.env.MINDLORE_HOME = tmpDir;
17
+ });
18
+ afterEach(() => {
19
+ if (origEnv === undefined)
20
+ delete process.env.MINDLORE_HOME;
21
+ else
22
+ process.env.MINDLORE_HOME = origEnv;
23
+ fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
24
+ });
25
+ describe('hookLog', () => {
26
+ test('writes JSONL entry to diary/_hook-log.jsonl', () => {
27
+ hookLog('test-hook', 'info', 'hello world');
28
+ const logPath = path_1.default.join(tmpDir, 'diary', '_hook-log.jsonl');
29
+ expect(fs_1.default.existsSync(logPath)).toBe(true);
30
+ const lines = fs_1.default.readFileSync(logPath, 'utf8').trim().split('\n');
31
+ expect(lines).toHaveLength(1);
32
+ const entry = JSON.parse(lines[0]);
33
+ expect(entry.hook).toBe('test-hook');
34
+ expect(entry.level).toBe('info');
35
+ expect(entry.msg).toBe('hello world');
36
+ expect(entry.ts).toBeDefined();
37
+ expect(entry.pid).toBe(process.pid);
38
+ });
39
+ test('appends multiple entries', () => {
40
+ hookLog('h1', 'info', 'first');
41
+ hookLog('h2', 'warn', 'second');
42
+ hookLog('h3', 'error', 'third');
43
+ const logPath = path_1.default.join(tmpDir, 'diary', '_hook-log.jsonl');
44
+ const lines = fs_1.default.readFileSync(logPath, 'utf8').trim().split('\n');
45
+ expect(lines).toHaveLength(3);
46
+ expect(JSON.parse(lines[1]).level).toBe('warn');
47
+ });
48
+ test('rotates when file exceeds 500KB', () => {
49
+ const logPath = path_1.default.join(tmpDir, 'diary', '_hook-log.jsonl');
50
+ // Write >500KB of data
51
+ const bigLine = JSON.stringify({ ts: new Date().toISOString(), hook: 'filler', level: 'info', msg: 'x'.repeat(200), pid: 1 });
52
+ const lines = Array(3000).fill(bigLine);
53
+ fs_1.default.writeFileSync(logPath, lines.join('\n') + '\n');
54
+ expect(fs_1.default.statSync(logPath).size).toBeGreaterThan(512 * 1024);
55
+ // hookLog should trigger rotation
56
+ hookLog('post-rotate', 'info', 'after rotation');
57
+ const content = fs_1.default.readFileSync(logPath, 'utf8').trim().split('\n');
58
+ // Should be trimmed to ~501 lines (500 kept + 1 new)
59
+ expect(content.length).toBeLessThanOrEqual(501);
60
+ expect(JSON.parse(content[content.length - 1]).hook).toBe('post-rotate');
61
+ });
62
+ test('does not crash when diary dir missing', () => {
63
+ fs_1.default.rmSync(path_1.default.join(tmpDir, 'diary'), { recursive: true, force: true });
64
+ expect(() => hookLog('no-dir', 'error', 'should not crash')).not.toThrow();
65
+ });
66
+ });
67
+ describe('getRecentHookErrors', () => {
68
+ test('returns empty when no log file', () => {
69
+ const errors = getRecentHookErrors();
70
+ expect(errors).toEqual([]);
71
+ });
72
+ test('returns only error and warn entries', () => {
73
+ hookLog('h1', 'info', 'ignored');
74
+ hookLog('h2', 'error', 'caught');
75
+ hookLog('h3', 'warn', 'also caught');
76
+ hookLog('h4', 'info', 'also ignored');
77
+ const errors = getRecentHookErrors();
78
+ expect(errors).toHaveLength(2);
79
+ expect(errors[0].level).toBe('error');
80
+ expect(errors[1].level).toBe('warn');
81
+ });
82
+ test('respects since cutoff', () => {
83
+ const logPath = path_1.default.join(tmpDir, 'diary', '_hook-log.jsonl');
84
+ // Write an old error
85
+ const oldEntry = JSON.stringify({ ts: '2020-01-01T00:00:00.000Z', hook: 'old', level: 'error', msg: 'ancient', pid: 1 });
86
+ fs_1.default.writeFileSync(logPath, oldEntry + '\n');
87
+ // Write a recent error
88
+ hookLog('new', 'error', 'recent');
89
+ const errors = getRecentHookErrors();
90
+ expect(errors).toHaveLength(1);
91
+ expect(errors[0].hook).toBe('new');
92
+ });
93
+ test('respects limit parameter', () => {
94
+ for (let i = 0; i < 20; i++) {
95
+ hookLog(`h${i}`, 'error', `err ${i}`);
96
+ }
97
+ const errors = getRecentHookErrors(undefined, 5);
98
+ expect(errors).toHaveLength(5);
99
+ });
100
+ test('returns chronological order', () => {
101
+ hookLog('first', 'error', 'a');
102
+ hookLog('second', 'error', 'b');
103
+ const errors = getRecentHookErrors();
104
+ expect(errors[0].hook).toBe('first');
105
+ expect(errors[1].hook).toBe('second');
106
+ });
107
+ });
108
+ //# sourceMappingURL=hook-logging.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-logging.test.js","sourceRoot":"","sources":["../../tests/hook-logging.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hybrid-search.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.test.d.ts","sourceRoot":"","sources":["../../tests/hybrid-search.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,114 @@
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-hybrid-search');
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('RRF Fusion', () => {
20
+ test('should compute RRF scores correctly', () => {
21
+ const { computeRRF } = require('../scripts/lib/hybrid-search.js');
22
+ const ftsResults = [
23
+ { slug: 'a', rank: -10 },
24
+ { slug: 'b', rank: -5 },
25
+ ];
26
+ const vecResults = [
27
+ { slug: 'b', distance: 0.5 },
28
+ { slug: 'c', distance: 0.8 },
29
+ ];
30
+ const fused = computeRRF(ftsResults, vecResults, { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
31
+ // 'b' appears in both — should have highest score
32
+ expect(fused[0].slug).toBe('b');
33
+ expect(fused.length).toBe(3); // a, b, c
34
+ // All scores should be positive
35
+ fused.forEach((r) => expect(r.score).toBeGreaterThan(0));
36
+ });
37
+ test('should handle FTS-only results (vec empty)', () => {
38
+ const { computeRRF } = require('../scripts/lib/hybrid-search.js');
39
+ const ftsResults = [
40
+ { slug: 'a', rank: -10 },
41
+ { slug: 'b', rank: -5 },
42
+ ];
43
+ const fused = computeRRF(ftsResults, [], { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
44
+ expect(fused.length).toBe(2);
45
+ expect(fused[0].slug).toBe('a');
46
+ });
47
+ test('should handle vec-only results (FTS empty)', () => {
48
+ const { computeRRF } = require('../scripts/lib/hybrid-search.js');
49
+ const vecResults = [
50
+ { slug: 'a', distance: 0.3 },
51
+ { slug: 'b', distance: 0.9 },
52
+ ];
53
+ const fused = computeRRF([], vecResults, { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
54
+ expect(fused.length).toBe(2);
55
+ expect(fused[0].slug).toBe('a'); // lower distance = more similar
56
+ });
57
+ test('should convert L2 distance to cosine similarity', () => {
58
+ const { l2ToCosine } = require('../scripts/lib/hybrid-search.js');
59
+ // L2 distance 0 = identical = cosine 1.0
60
+ expect(l2ToCosine(0)).toBeCloseTo(1.0, 5);
61
+ // L2 distance 2 = opposite = cosine 0.0 (for normalized vectors)
62
+ expect(l2ToCosine(2)).toBeCloseTo(0.0, 5);
63
+ // L2 distance 1 (90 degrees for normalized) = cosine 0.5
64
+ expect(l2ToCosine(1)).toBeCloseTo(0.5, 5);
65
+ });
66
+ test('should normalize BM25 scores', () => {
67
+ const { normalizeBM25 } = require('../scripts/lib/hybrid-search.js');
68
+ // FTS5 returns negative ranks — more negative = better match
69
+ expect(normalizeBM25(-25)).toBeCloseTo(1.0, 5);
70
+ expect(normalizeBM25(-12.5)).toBeCloseTo(0.5, 5);
71
+ expect(normalizeBM25(0)).toBeCloseTo(0.0, 5);
72
+ });
73
+ });
74
+ describe('Hybrid Search Integration', () => {
75
+ test('should search FTS5 and return results with path and score', () => {
76
+ const { searchFts5 } = require('../scripts/lib/hybrid-search.js');
77
+ const db = new better_sqlite3_1.default(DB_PATH);
78
+ (0, db_js_1.insertFts)(db, {
79
+ path: path_1.default.join(TEST_DIR, 'sources', 'test.md'),
80
+ slug: 'test-doc',
81
+ description: 'TypeScript guide for beginners',
82
+ type: 'source',
83
+ category: 'sources',
84
+ title: 'Test Doc',
85
+ content: 'TypeScript is a typed superset of JavaScript',
86
+ tags: 'typescript,javascript',
87
+ });
88
+ const results = searchFts5(db, 'TypeScript', 10);
89
+ expect(results.length).toBe(1);
90
+ expect(results[0].slug).toBe('test-doc');
91
+ expect(results[0].rank).toBeDefined();
92
+ db.close();
93
+ });
94
+ test('should fall back to pure FTS5 when vec table is missing', () => {
95
+ const { hybridSearch } = require('../scripts/lib/hybrid-search.js');
96
+ const db = new better_sqlite3_1.default(DB_PATH);
97
+ (0, db_js_1.insertFts)(db, {
98
+ path: path_1.default.join(TEST_DIR, 'sources', 'fallback.md'),
99
+ slug: 'fallback-doc',
100
+ description: 'Fallback test document',
101
+ type: 'source',
102
+ category: 'sources',
103
+ title: 'Fallback Doc',
104
+ content: 'This tests the graceful fallback to pure FTS5',
105
+ tags: 'test',
106
+ });
107
+ // No vec table loaded — should still work via FTS5 fallback
108
+ const results = hybridSearch(db, 'fallback', { maxResults: 5 });
109
+ expect(results.length).toBe(1);
110
+ expect(results[0].slug).toBe('fallback-doc');
111
+ db.close();
112
+ });
113
+ });
114
+ //# sourceMappingURL=hybrid-search.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.test.js","sourceRoot":"","sources":["../../tests/hybrid-search.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for embedding pipeline used by --embed flag in index script.
3
+ * Tests the library functions (embedding.ts, db-helpers.ts vec functions)
4
+ * rather than the CLI subprocess.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index-cli-embed.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-cli-embed.test.d.ts","sourceRoot":"","sources":["../../tests/index-cli-embed.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for embedding pipeline used by --embed flag in index script.
4
+ * Tests the library functions (embedding.ts, db-helpers.ts vec functions)
5
+ * rather than the CLI subprocess.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ const path_1 = __importDefault(require("path"));
12
+ const db_js_1 = require("./helpers/db.js");
13
+ const { hasVecTable, dbAll: dbAllFn } = require('../scripts/lib/db-helpers.js');
14
+ const { searchFts5, searchVec, hybridSearch } = require('../scripts/lib/hybrid-search.js');
15
+ const TEST_DIR = path_1.default.join(__dirname, '..', '.test-index-cli-embed');
16
+ const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
17
+ beforeEach(() => {
18
+ (0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
19
+ });
20
+ afterEach(() => {
21
+ (0, db_js_1.teardownTestDir)(TEST_DIR);
22
+ });
23
+ describe('Embedding Pipeline — vec table management', () => {
24
+ test('should create vec table when sqlite-vec is available', () => {
25
+ const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
26
+ if (vecLoaded) {
27
+ expect(hasVecTable(db)).toBe(true);
28
+ }
29
+ else {
30
+ expect(hasVecTable(db)).toBe(false);
31
+ }
32
+ db.close();
33
+ });
34
+ test('should handle missing sqlite-vec gracefully', () => {
35
+ const db = (0, db_js_1.createTestDb)(DB_PATH);
36
+ expect(hasVecTable(db)).toBe(false);
37
+ db.close();
38
+ });
39
+ test('should insert and query vec embeddings when vec is available', () => {
40
+ const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
41
+ if (!vecLoaded) {
42
+ db.close();
43
+ return;
44
+ }
45
+ const testEmbedding = new Float32Array(384);
46
+ testEmbedding[0] = 1.0;
47
+ (0, db_js_1.insertVec)(db, 'test-doc', testEmbedding, 'test-model');
48
+ const rows = dbAllFn(db, 'SELECT slug FROM documents_vec WHERE slug = ?', 'test-doc');
49
+ expect(rows).toHaveLength(1);
50
+ expect(rows[0]?.slug).toBe('test-doc');
51
+ db.close();
52
+ });
53
+ test('should search vec table with embedding match when available', () => {
54
+ const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
55
+ if (!vecLoaded) {
56
+ db.close();
57
+ return;
58
+ }
59
+ const embed1 = new Float32Array(384);
60
+ embed1[0] = 1.0;
61
+ (0, db_js_1.insertVec)(db, 'doc-a', embed1, 'test-model');
62
+ const embed2 = new Float32Array(384);
63
+ embed2[1] = 1.0;
64
+ (0, db_js_1.insertVec)(db, 'doc-b', embed2, 'test-model');
65
+ const queryEmbed = new Float32Array(384);
66
+ queryEmbed[0] = 0.9;
67
+ const results = searchVec(db, Array.from(queryEmbed), 5);
68
+ expect(results.length).toBe(2);
69
+ expect(results[0].slug).toBe('doc-a');
70
+ db.close();
71
+ });
72
+ });
73
+ describe('Embedding Pipeline — FTS5 + vec coexistence', () => {
74
+ test('should allow FTS5 and vec tables in same database', () => {
75
+ const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
76
+ (0, db_js_1.insertFts)(db, {
77
+ path: path_1.default.join(TEST_DIR, 'sources', 'coexist.md'),
78
+ slug: 'coexist-doc',
79
+ description: 'Test coexistence of FTS5 and vec tables',
80
+ type: 'source',
81
+ category: 'sources',
82
+ title: 'Coexist Doc',
83
+ content: 'Testing that both FTS5 and vec work together',
84
+ tags: 'test',
85
+ });
86
+ const ftsResults = searchFts5(db, 'coexistence', 5);
87
+ expect(ftsResults.length).toBeGreaterThan(0);
88
+ if (vecLoaded) {
89
+ const testEmbed = new Float32Array(384);
90
+ testEmbed[0] = 1.0;
91
+ (0, db_js_1.insertVec)(db, 'coexist-doc', testEmbed, 'test-model');
92
+ expect(hasVecTable(db)).toBe(true);
93
+ }
94
+ db.close();
95
+ });
96
+ test('should run hybridSearch with both FTS5 data and vec embeddings', () => {
97
+ const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
98
+ (0, db_js_1.insertFts)(db, {
99
+ path: path_1.default.join(TEST_DIR, 'sources', 'hybrid-test.md'),
100
+ slug: 'hybrid-test',
101
+ description: 'Document for hybrid search integration test',
102
+ type: 'source',
103
+ category: 'sources',
104
+ title: 'Hybrid Test',
105
+ content: 'Hybrid search combines FTS5 keyword and vector semantic results',
106
+ tags: 'hybrid,search',
107
+ });
108
+ if (vecLoaded) {
109
+ const testEmbed = new Float32Array(384);
110
+ testEmbed[0] = 1.0;
111
+ (0, db_js_1.insertVec)(db, 'hybrid-test', testEmbed, 'test-model');
112
+ }
113
+ let queryEmbed;
114
+ if (vecLoaded) {
115
+ const q = new Float32Array(384);
116
+ q[0] = 0.9;
117
+ queryEmbed = Array.from(q);
118
+ }
119
+ const results = hybridSearch(db, 'hybrid search', {
120
+ maxResults: 5,
121
+ queryEmbedding: queryEmbed,
122
+ });
123
+ expect(results.length).toBeGreaterThan(0);
124
+ expect(results[0].slug).toBe('hybrid-test');
125
+ db.close();
126
+ });
127
+ });
128
+ //# sourceMappingURL=index-cli-embed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-cli-embed.test.js","sourceRoot":"","sources":["../../tests/index-cli-embed.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=privacy-filter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy-filter.test.d.ts","sourceRoot":"","sources":["../../tests/privacy-filter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const privacy_filter_js_1 = require("../scripts/lib/privacy-filter.js");
4
+ describe('Privacy Filter', () => {
5
+ test('should redact OpenAI API keys', () => {
6
+ const input = 'My key is sk-proj-abc123def456ghi789';
7
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
8
+ expect(result).toBe('My key is [REDACTED]');
9
+ expect(result).not.toContain('sk-proj-');
10
+ });
11
+ test('should redact AWS access keys', () => {
12
+ const input = 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE';
13
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
14
+ expect(result).toContain('[REDACTED]');
15
+ expect(result).not.toContain('AKIA');
16
+ });
17
+ test('should redact GitHub tokens', () => {
18
+ const input = 'token: ghp_ABCDEFghijklmnop1234567890abcdefGHIJ';
19
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
20
+ expect(result).toContain('[REDACTED]');
21
+ expect(result).not.toContain('ghp_');
22
+ });
23
+ test('should redact npm tokens', () => {
24
+ const input = 'npm_abc123DEF456ghi789JKL012mno345PQR678stu';
25
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
26
+ expect(result).toContain('[REDACTED]');
27
+ });
28
+ test('should redact connection strings', () => {
29
+ const input = 'DB_URL=postgres://user:pass@host:5432/db';
30
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
31
+ expect(result).toContain('[REDACTED]');
32
+ expect(result).not.toContain('pass@');
33
+ });
34
+ test('should redact .env style secrets', () => {
35
+ const input = 'DATABASE_PASSWORD=supersecret123\nAPI_TOKEN=mytoken456';
36
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
37
+ expect(result).not.toContain('supersecret123');
38
+ expect(result).not.toContain('mytoken456');
39
+ });
40
+ test('should not redact normal text', () => {
41
+ const input = 'This is a normal document about authentication patterns.';
42
+ const result = (0, privacy_filter_js_1.redactSecrets)(input);
43
+ expect(result).toBe(input);
44
+ });
45
+ test('should accept custom patterns from config', () => {
46
+ const input = 'CUSTOM_KEY=abc123';
47
+ const custom = [/CUSTOM_KEY=\S+/g];
48
+ const result = (0, privacy_filter_js_1.redactSecrets)(input, custom);
49
+ expect(result).toContain('[REDACTED]');
50
+ });
51
+ test('should export DEFAULT_PATTERNS array', () => {
52
+ expect(Array.isArray(privacy_filter_js_1.DEFAULT_PATTERNS)).toBe(true);
53
+ expect(privacy_filter_js_1.DEFAULT_PATTERNS.length).toBeGreaterThan(0);
54
+ });
55
+ });
56
+ //# sourceMappingURL=privacy-filter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy-filter.test.js","sourceRoot":"","sources":["../../tests/privacy-filter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schema-version.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-version.test.d.ts","sourceRoot":"","sources":["../../tests/schema-version.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
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 migrations_v051_js_1 = require("../scripts/lib/migrations-v051.js");
10
+ const TEST_DIR = path_1.default.join(__dirname, '..', '.test-schema-version');
11
+ const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
12
+ beforeEach(() => {
13
+ (0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
14
+ const db = (0, db_js_1.createTestDb)(DB_PATH);
15
+ db.close();
16
+ });
17
+ afterEach(() => {
18
+ (0, db_js_1.teardownTestDir)(TEST_DIR);
19
+ });
20
+ describe('Schema Version', () => {
21
+ test('should create schema_versions table if missing', () => {
22
+ const { ensureSchemaTable, getSchemaVersion } = require('../scripts/lib/schema-version.js');
23
+ const db = new better_sqlite3_1.default(DB_PATH);
24
+ ensureSchemaTable(db);
25
+ const version = getSchemaVersion(db);
26
+ expect(version).toBe(0);
27
+ db.close();
28
+ });
29
+ test('should set and get schema version', () => {
30
+ const { ensureSchemaTable, setSchemaVersion, getSchemaVersion } = require('../scripts/lib/schema-version.js');
31
+ const db = new better_sqlite3_1.default(DB_PATH);
32
+ ensureSchemaTable(db);
33
+ setSchemaVersion(db, 1);
34
+ expect(getSchemaVersion(db)).toBe(1);
35
+ db.close();
36
+ });
37
+ test('should run migrations in order', () => {
38
+ const { ensureSchemaTable, runMigrations, getSchemaVersion } = require('../scripts/lib/schema-version.js');
39
+ const db = new better_sqlite3_1.default(DB_PATH);
40
+ ensureSchemaTable(db);
41
+ const log = [];
42
+ const migrations = [
43
+ { version: 1, name: 'add_timestamps', up: (d) => { log.push(1); d.exec("SELECT 1"); } },
44
+ { version: 2, name: 'add_vec_table', up: (d) => { log.push(2); d.exec("SELECT 1"); } },
45
+ ];
46
+ runMigrations(db, migrations);
47
+ expect(getSchemaVersion(db)).toBe(2);
48
+ expect(log).toEqual([1, 2]);
49
+ db.close();
50
+ });
51
+ test('should skip already-applied migrations', () => {
52
+ const { ensureSchemaTable, setSchemaVersion, runMigrations, getSchemaVersion } = require('../scripts/lib/schema-version.js');
53
+ const db = new better_sqlite3_1.default(DB_PATH);
54
+ ensureSchemaTable(db);
55
+ setSchemaVersion(db, 1);
56
+ const log = [];
57
+ const migrations = [
58
+ { version: 1, name: 'add_timestamps', up: () => { log.push(1); } },
59
+ { version: 2, name: 'add_vec_table', up: () => { log.push(2); } },
60
+ ];
61
+ runMigrations(db, migrations);
62
+ expect(getSchemaVersion(db)).toBe(2);
63
+ expect(log).toEqual([2]); // only migration 2 ran
64
+ db.close();
65
+ });
66
+ });
67
+ describe('v0.5.0 Migrations', () => {
68
+ test('should create documents_vec table via migration', () => {
69
+ const { ensureSchemaTable, runMigrations, getSchemaVersion } = require('../scripts/lib/schema-version.js');
70
+ const { V050_MIGRATIONS } = require('../scripts/lib/migrations.js');
71
+ const { loadSqliteVec } = require('../scripts/lib/db-helpers.js');
72
+ const db = new better_sqlite3_1.default(DB_PATH);
73
+ loadSqliteVec(db);
74
+ ensureSchemaTable(db);
75
+ runMigrations(db, V050_MIGRATIONS);
76
+ expect(getSchemaVersion(db)).toBe(1);
77
+ // Verify vec table exists
78
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test: better-sqlite3 .get() returns unknown
79
+ const row = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='documents_vec'").get();
80
+ expect(row?.name).toBe('documents_vec');
81
+ db.close();
82
+ });
83
+ test('should add created_at and updated_at to FTS metadata tracking', () => {
84
+ const { ensureSchemaTable, runMigrations } = require('../scripts/lib/schema-version.js');
85
+ const { V050_MIGRATIONS } = require('../scripts/lib/migrations.js');
86
+ const { loadSqliteVec } = require('../scripts/lib/db-helpers.js');
87
+ const db = new better_sqlite3_1.default(DB_PATH);
88
+ loadSqliteVec(db);
89
+ ensureSchemaTable(db);
90
+ runMigrations(db, V050_MIGRATIONS);
91
+ // file_hashes should now have created_at column
92
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test: pragma returns array of objects
93
+ const info = db.pragma('table_info(file_hashes)');
94
+ const colNames = info.map(c => c.name);
95
+ expect(colNames).toContain('created_at');
96
+ expect(colNames).toContain('updated_at');
97
+ db.close();
98
+ });
99
+ });
100
+ describe('v0.5.1 Migrations', () => {
101
+ test('should add source_type column to file_hashes', () => {
102
+ const { ensureSchemaTable, runMigrations } = require('../scripts/lib/schema-version.js');
103
+ const { V050_MIGRATIONS } = require('../scripts/lib/migrations.js');
104
+ const db = new better_sqlite3_1.default(DB_PATH);
105
+ ensureSchemaTable(db);
106
+ runMigrations(db, [...V050_MIGRATIONS, ...migrations_v051_js_1.V051_MIGRATIONS]);
107
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test: pragma returns array of objects
108
+ const cols = db.pragma('table_info(file_hashes)');
109
+ const colNames = cols.map(c => c.name);
110
+ expect(colNames).toContain('source_type');
111
+ expect(colNames).toContain('project_scope');
112
+ expect(colNames).toContain('content_hash');
113
+ db.close();
114
+ });
115
+ test('should be idempotent — running twice does not error', () => {
116
+ const { ensureSchemaTable, runMigrations, getSchemaVersion } = require('../scripts/lib/schema-version.js');
117
+ const { V050_MIGRATIONS } = require('../scripts/lib/migrations.js');
118
+ const db = new better_sqlite3_1.default(DB_PATH);
119
+ ensureSchemaTable(db);
120
+ runMigrations(db, [...V050_MIGRATIONS, ...migrations_v051_js_1.V051_MIGRATIONS]);
121
+ runMigrations(db, [...V050_MIGRATIONS, ...migrations_v051_js_1.V051_MIGRATIONS]);
122
+ const version = getSchemaVersion(db);
123
+ expect(version).toBeGreaterThanOrEqual(2);
124
+ db.close();
125
+ });
126
+ });
127
+ //# sourceMappingURL=schema-version.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-version.test.js","sourceRoot":"","sources":["../../tests/schema-version.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests for hybrid search CLI path — tests the library functions
3
+ * that --hybrid flag invokes (synonym expansion + hybridSearch integration).
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=search-cli-hybrid.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-cli-hybrid.test.d.ts","sourceRoot":"","sources":["../../tests/search-cli-hybrid.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}