mindlore 0.6.7 → 0.6.8
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 +259 -259
- package/SCHEMA.md +292 -292
- package/dist/scripts/cc-memory-bulk-sync.d.ts.map +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js +47 -42
- package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
- package/dist/scripts/cc-session-sync.d.ts.map +1 -1
- package/dist/scripts/cc-session-sync.js +58 -48
- package/dist/scripts/cc-session-sync.js.map +1 -1
- package/dist/scripts/init.js +8 -8
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/all-migrations.d.ts.map +1 -1
- package/dist/scripts/lib/all-migrations.js +4 -1
- package/dist/scripts/lib/all-migrations.js.map +1 -1
- package/dist/scripts/lib/consolidation.d.ts +4 -3
- package/dist/scripts/lib/consolidation.d.ts.map +1 -1
- package/dist/scripts/lib/consolidation.js +10 -10
- package/dist/scripts/lib/consolidation.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +1 -7
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +2 -9
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/db-helpers.d.ts +0 -15
- package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
- package/dist/scripts/lib/db-helpers.js +1 -51
- package/dist/scripts/lib/db-helpers.js.map +1 -1
- package/dist/scripts/lib/decay.d.ts.map +1 -1
- package/dist/scripts/lib/decay.js +9 -9
- package/dist/scripts/lib/decay.js.map +1 -1
- package/dist/scripts/lib/episodes.js +23 -23
- package/dist/scripts/lib/migrations-v061.js +21 -21
- package/dist/scripts/lib/migrations-v062.js +11 -11
- package/dist/scripts/lib/migrations-v063.js +14 -14
- package/dist/scripts/lib/migrations-v067.js +11 -11
- package/dist/scripts/lib/migrations-v068.d.ts +3 -0
- package/dist/scripts/lib/migrations-v068.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v068.js +37 -0
- package/dist/scripts/lib/migrations-v068.js.map +1 -0
- package/dist/scripts/lib/migrations.d.ts.map +1 -1
- package/dist/scripts/lib/migrations.js +0 -15
- package/dist/scripts/lib/migrations.js.map +1 -1
- package/dist/scripts/lib/schema-version.js +6 -6
- package/dist/scripts/lib/search-cache.js +11 -11
- package/dist/scripts/lib/session-payload.d.ts.map +1 -1
- package/dist/scripts/lib/session-payload.js +7 -7
- package/dist/scripts/lib/session-payload.js.map +1 -1
- package/dist/scripts/lib/triage.js +3 -3
- package/dist/scripts/mindlore-backup.js +9 -9
- package/dist/scripts/mindlore-fts5-index.d.ts +1 -2
- package/dist/scripts/mindlore-fts5-index.d.ts.map +1 -1
- package/dist/scripts/mindlore-fts5-index.js +12 -64
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +0 -11
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/tests/cc-memory-bulk-sync.test.js +23 -0
- package/dist/tests/cc-memory-bulk-sync.test.js.map +1 -1
- package/dist/tests/cc-session-sync.test.js +25 -0
- package/dist/tests/cc-session-sync.test.js.map +1 -1
- package/dist/tests/compaction-snapshot.test.js +2 -2
- package/dist/tests/consolidation.test.js +5 -5
- package/dist/tests/consolidation.test.js.map +1 -1
- package/dist/tests/decay.test.js +9 -9
- package/dist/tests/diary.test.js +4 -4
- package/dist/tests/episode-kind-constant.test.d.ts +2 -0
- package/dist/tests/episode-kind-constant.test.d.ts.map +1 -0
- package/dist/tests/episode-kind-constant.test.js +28 -0
- package/dist/tests/episode-kind-constant.test.js.map +1 -0
- package/dist/tests/episodes-inject.test.js +9 -9
- package/dist/tests/fts5.test.js +66 -125
- package/dist/tests/fts5.test.js.map +1 -1
- package/dist/tests/globalSetup.d.ts +2 -0
- package/dist/tests/globalSetup.d.ts.map +1 -0
- package/dist/tests/globalSetup.js +36 -0
- package/dist/tests/globalSetup.js.map +1 -0
- package/dist/tests/helpers/db.d.ts +13 -5
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +60 -33
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/lesson-graduation.test.js +11 -11
- package/dist/tests/lesson-graduation.test.js.map +1 -1
- package/dist/tests/migrations-v053.test.js +16 -16
- package/dist/tests/migrations-v061.test.js +10 -10
- package/dist/tests/migrations-v063.test.js +2 -2
- package/dist/tests/migrations-v068.test.d.ts +2 -0
- package/dist/tests/migrations-v068.test.d.ts.map +1 -0
- package/dist/tests/migrations-v068.test.js +53 -0
- package/dist/tests/migrations-v068.test.js.map +1 -0
- package/dist/tests/nomination-counts.test.d.ts +2 -0
- package/dist/tests/nomination-counts.test.d.ts.map +1 -0
- package/dist/tests/nomination-counts.test.js +51 -0
- package/dist/tests/nomination-counts.test.js.map +1 -0
- package/dist/tests/recall-telemetry.test.js +8 -8
- package/dist/tests/schema-version.test.js +3 -7
- package/dist/tests/schema-version.test.js.map +1 -1
- package/dist/tests/search-hook.test.js +2 -2
- package/dist/tests/sec-regression.test.js +0 -50
- package/dist/tests/sec-regression.test.js.map +1 -1
- package/dist/tests/session-end-cleanup.test.js +3 -20
- package/dist/tests/session-end-cleanup.test.js.map +1 -1
- package/dist/tests/session-focus.test.js +7 -30
- package/dist/tests/session-focus.test.js.map +1 -1
- package/dist/tests/session-payload.test.js +1 -1
- package/dist/tests/session-summary.test.js +1 -1
- package/hooks/lib/constants.cjs +15 -0
- package/hooks/lib/mindlore-common.cjs +974 -1042
- package/hooks/mindlore-cwd-changed.cjs +57 -57
- package/hooks/mindlore-decision-detector.cjs +54 -54
- package/hooks/mindlore-dont-repeat.cjs +222 -222
- package/hooks/mindlore-fts5-sync.cjs +97 -88
- package/hooks/mindlore-index.cjs +229 -229
- package/hooks/mindlore-model-router.cjs +54 -54
- package/hooks/mindlore-post-compact.cjs +69 -69
- package/hooks/mindlore-post-read.cjs +106 -106
- package/hooks/mindlore-pre-compact.cjs +154 -154
- package/hooks/mindlore-read-guard.cjs +105 -105
- package/hooks/mindlore-research-guard.cjs +176 -176
- package/hooks/mindlore-search.cjs +200 -200
- package/hooks/mindlore-session-end.cjs +509 -526
- package/hooks/mindlore-session-focus.cjs +256 -259
- package/package.json +75 -78
- package/plugin.json +1 -1
- package/skills/mindlore-diary/SKILL.md +85 -85
- package/skills/mindlore-evolve/SKILL.md +126 -126
- package/skills/mindlore-explore/SKILL.md +109 -109
- package/skills/mindlore-ingest/SKILL.md +195 -195
- package/skills/mindlore-maintain/SKILL.md +125 -125
- package/skills/mindlore-query/SKILL.md +151 -151
- package/skills/mindlore-reflect/SKILL.md +141 -141
- package/skills/mindlore-stats/SKILL.md +106 -106
- package/templates/INDEX.md +14 -14
- package/templates/SCHEMA.md +292 -292
- package/templates/config.json +1 -1
- package/templates/extraction/article.md +15 -15
- package/templates/extraction/changelog.md +15 -15
- package/templates/extraction/default.md +15 -15
- package/templates/extraction/docs.md +15 -15
- package/templates/extraction/github-repo.md +17 -17
- package/dist/scripts/lib/daemon.d.ts +0 -16
- package/dist/scripts/lib/daemon.d.ts.map +0 -1
- package/dist/scripts/lib/daemon.js +0 -133
- package/dist/scripts/lib/daemon.js.map +0 -1
- package/dist/scripts/lib/embedding.d.ts +0 -5
- package/dist/scripts/lib/embedding.d.ts.map +0 -1
- package/dist/scripts/lib/embedding.js +0 -44
- package/dist/scripts/lib/embedding.js.map +0 -1
- package/dist/scripts/mindlore-daemon.d.ts +0 -2
- package/dist/scripts/mindlore-daemon.d.ts.map +0 -1
- package/dist/scripts/mindlore-daemon.js +0 -117
- package/dist/scripts/mindlore-daemon.js.map +0 -1
- package/dist/tests/daemon-integration.test.d.ts +0 -2
- package/dist/tests/daemon-integration.test.d.ts.map +0 -1
- package/dist/tests/daemon-integration.test.js +0 -37
- package/dist/tests/daemon-integration.test.js.map +0 -1
- package/dist/tests/daemon.test.d.ts +0 -2
- package/dist/tests/daemon.test.d.ts.map +0 -1
- package/dist/tests/daemon.test.js +0 -187
- package/dist/tests/daemon.test.js.map +0 -1
- package/dist/tests/embedding-hf-integration.test.d.ts +0 -2
- package/dist/tests/embedding-hf-integration.test.d.ts.map +0 -1
- package/dist/tests/embedding-hf-integration.test.js +0 -52
- package/dist/tests/embedding-hf-integration.test.js.map +0 -1
- package/dist/tests/embedding.test.d.ts +0 -6
- package/dist/tests/embedding.test.d.ts.map +0 -1
- package/dist/tests/embedding.test.js +0 -71
- package/dist/tests/embedding.test.js.map +0 -1
- package/dist/tests/sqlite-vec-v12.test.d.ts +0 -2
- package/dist/tests/sqlite-vec-v12.test.d.ts.map +0 -1
- package/dist/tests/sqlite-vec-v12.test.js +0 -72
- package/dist/tests/sqlite-vec-v12.test.js.map +0 -1
|
@@ -22,9 +22,9 @@ afterEach(() => {
|
|
|
22
22
|
(0, db_js_1.destroyEpisodesTestEnv)(env);
|
|
23
23
|
});
|
|
24
24
|
function insertEpisode(db, opts) {
|
|
25
|
-
db.prepare(`
|
|
26
|
-
INSERT INTO episodes (id, kind, scope, summary, status, created_at, consolidation_status)
|
|
27
|
-
VALUES (?, ?, 'project', ?, ?, ?, ?)
|
|
25
|
+
db.prepare(`
|
|
26
|
+
INSERT INTO episodes (id, kind, scope, summary, status, created_at, consolidation_status)
|
|
27
|
+
VALUES (?, ?, 'project', ?, ?, ?, ?)
|
|
28
28
|
`).run(opts.id, opts.kind, opts.summary, opts.status ?? 'active', new Date().toISOString(), opts.consolidation_status ?? 'raw');
|
|
29
29
|
}
|
|
30
30
|
describe('countRawEpisodes', () => {
|
|
@@ -41,12 +41,12 @@ describe('groupEpisodesByKind', () => {
|
|
|
41
41
|
insertEpisode(env.db, { id: 'ep-2', kind: 'session', summary: 'Session B' });
|
|
42
42
|
insertEpisode(env.db, { id: 'ep-3', kind: 'decision', summary: 'Decision A' });
|
|
43
43
|
insertEpisode(env.db, { id: 'ep-4', kind: 'session', summary: 'Consolidated', consolidation_status: 'consolidated' });
|
|
44
|
-
insertEpisode(env.db, { id: 'ep-5', kind: '
|
|
44
|
+
insertEpisode(env.db, { id: 'ep-5', kind: 'learning', summary: 'Inactive', status: 'inactive' });
|
|
45
45
|
const groups = (0, consolidation_js_1.groupEpisodesByKind)(env.db);
|
|
46
46
|
expect(groups.size).toBe(2);
|
|
47
47
|
expect(groups.get('session')).toHaveLength(2);
|
|
48
48
|
expect(groups.get('decision')).toHaveLength(1);
|
|
49
|
-
expect(groups.has('
|
|
49
|
+
expect(groups.has('learning')).toBe(false);
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
52
|
describe('markConsolidated', () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consolidation.test.js","sourceRoot":"","sources":["../../tests/consolidation.test.ts"],"names":[],"mappings":";;AAAA,2CAAgF;AAEhF,wEAAoF;AACpF,gEAA+D;AAC/D,0EAAoE;AACpE,0EAAoE;AACpE,0EAAoE;AACpE,sEAKyC;
|
|
1
|
+
{"version":3,"file":"consolidation.test.js","sourceRoot":"","sources":["../../tests/consolidation.test.ts"],"names":[],"mappings":"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"}
|
package/dist/tests/decay.test.js
CHANGED
|
@@ -95,7 +95,7 @@ describe('recall shield', () => {
|
|
|
95
95
|
});
|
|
96
96
|
describe('archiveDocument / restoreDocument', () => {
|
|
97
97
|
test('archiveDocument sets archived_at, restoreDocument clears it', () => {
|
|
98
|
-
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
98
|
+
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
99
99
|
VALUES (?, ?, ?, ?, ?, ?)`).run('/test/doc.md', 'abc123', new Date().toISOString(), 0, null, 1.0);
|
|
100
100
|
(0, decay_js_1.archiveDocument)(db, '/test/doc.md');
|
|
101
101
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown, narrowing to expected row shape
|
|
@@ -112,10 +112,10 @@ describe('listStaleDocuments', () => {
|
|
|
112
112
|
const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString();
|
|
113
113
|
const now = new Date().toISOString();
|
|
114
114
|
// Stale: old, never recalled
|
|
115
|
-
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
115
|
+
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
116
116
|
VALUES (?, ?, ?, ?, ?, ?)`).run('/test/stale.md', 'hash1', ninetyDaysAgo, 0, null, 1.0);
|
|
117
117
|
// Active: recently recalled with high recall_count
|
|
118
|
-
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
118
|
+
db.prepare(`INSERT INTO file_hashes (path, content_hash, last_indexed, recall_count, last_recalled_at, importance)
|
|
119
119
|
VALUES (?, ?, ?, ?, ?, ?)`).run('/test/active.md', 'hash2', now, 20, now, 1.0);
|
|
120
120
|
const stale = (0, decay_js_1.listStaleDocuments)(db, 0.3);
|
|
121
121
|
const paths = stale.map(d => d.path);
|
|
@@ -129,7 +129,7 @@ describe('listStaleDocuments', () => {
|
|
|
129
129
|
});
|
|
130
130
|
describe('persistDecayScores', () => {
|
|
131
131
|
test('should write decay_score and last_decay_calc to episodes', () => {
|
|
132
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
132
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
133
133
|
VALUES ('test-decay-1', 'learning', 'project', 'test', datetime('now'))`).run();
|
|
134
134
|
(0, decay_js_1.persistDecayScores)(db);
|
|
135
135
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
@@ -139,15 +139,15 @@ describe('persistDecayScores', () => {
|
|
|
139
139
|
expect(row.last_decay_calc).toBeTruthy();
|
|
140
140
|
});
|
|
141
141
|
test('should return count of updated episodes', () => {
|
|
142
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
142
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
143
143
|
VALUES ('test-decay-2', 'decision', 'project', 'decision test', datetime('now'))`).run();
|
|
144
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
144
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
145
145
|
VALUES ('test-decay-3', 'observation', 'project', 'obs test', datetime('now'))`).run();
|
|
146
146
|
const count = (0, decay_js_1.persistDecayScores)(db);
|
|
147
147
|
expect(count).toBe(2);
|
|
148
148
|
});
|
|
149
149
|
test('should skip non-active episodes', () => {
|
|
150
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, status, created_at)
|
|
150
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, status, created_at)
|
|
151
151
|
VALUES ('test-decay-4', 'learning', 'project', 'archived', 'archived', datetime('now'))`).run();
|
|
152
152
|
const count = (0, decay_js_1.persistDecayScores)(db);
|
|
153
153
|
expect(count).toBe(0);
|
|
@@ -157,9 +157,9 @@ describe('persistDecayScores', () => {
|
|
|
157
157
|
});
|
|
158
158
|
test('should assign higher importance to learning and decision kinds', () => {
|
|
159
159
|
const oldDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
160
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
160
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
161
161
|
VALUES ('decay-learn', 'learning', 'project', 'learn', ?)`).run(oldDate);
|
|
162
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
162
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, summary, created_at)
|
|
163
163
|
VALUES ('decay-obs', 'observation', 'project', 'obs', ?)`).run(oldDate);
|
|
164
164
|
(0, decay_js_1.persistDecayScores)(db);
|
|
165
165
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
package/dist/tests/diary.test.js
CHANGED
|
@@ -100,9 +100,9 @@ describe('diary workflow: bare session → enriched episodes', () => {
|
|
|
100
100
|
});
|
|
101
101
|
test('finding latest bare session for diary analysis', () => {
|
|
102
102
|
// Simulate multiple sessions
|
|
103
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
103
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
104
104
|
VALUES ('ep-old', 'session', 'project', 'mindlore', 'Old session', 'active', 'hook', '2026-04-12T10:00:00.000Z')`).run();
|
|
105
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
105
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
106
106
|
VALUES ('ep-new', 'session', 'project', 'mindlore', 'Latest session', 'active', 'hook', '2026-04-13T15:00:00.000Z')`).run();
|
|
107
107
|
// Query like diary would: find latest session episode
|
|
108
108
|
const sessions = queryRecentEpisodes(db, { project: 'mindlore', limit: 1 });
|
|
@@ -154,9 +154,9 @@ describe('reflect input: episodes query', () => {
|
|
|
154
154
|
expect(reflectInput.some(e => e.source === 'reflect')).toBe(false);
|
|
155
155
|
});
|
|
156
156
|
test('reflect filters by date range', () => {
|
|
157
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
157
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
158
158
|
VALUES ('ep-old', 'friction', 'project', 'mindlore', 'Old friction', 'active', 'diary', '2026-04-01T10:00:00.000Z')`).run();
|
|
159
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
159
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
160
160
|
VALUES ('ep-recent', 'friction', 'project', 'mindlore', 'Recent friction', 'active', 'diary', '2026-04-13T10:00:00.000Z')`).run();
|
|
161
161
|
const lastWeek = (0, episodes_js_1.queryEpisodes)(db, {
|
|
162
162
|
project: 'mindlore',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"episode-kind-constant.test.d.ts","sourceRoot":"","sources":["../../tests/episode-kind-constant.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
describe('Episode kind shared constant', () => {
|
|
4
|
+
test('CJS and TS share the same kinds array', () => {
|
|
5
|
+
const { EPISODE_KINDS: cjsKinds } = require('../hooks/lib/constants.cjs');
|
|
6
|
+
const { EPISODE_KINDS: tsKinds } = require('../scripts/lib/episodes.js');
|
|
7
|
+
expect(cjsKinds).toEqual([...tsKinds]);
|
|
8
|
+
});
|
|
9
|
+
test('isValidKind validates correctly', () => {
|
|
10
|
+
const { isValidKind } = require('../hooks/lib/constants.cjs');
|
|
11
|
+
expect(isValidKind('nomination')).toBe(true);
|
|
12
|
+
expect(isValidKind('invalid-kind')).toBe(false);
|
|
13
|
+
expect(isValidKind('')).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
describe('DB_BUSY_TIMEOUT_MS shared constant', () => {
|
|
17
|
+
test('CJS and TS export the same value', () => {
|
|
18
|
+
const { DB_BUSY_TIMEOUT_MS: cjsTimeout } = require('../hooks/lib/constants.cjs');
|
|
19
|
+
const { DB_BUSY_TIMEOUT_MS: tsTimeout } = require('../scripts/lib/constants.js');
|
|
20
|
+
expect(cjsTimeout).toBe(tsTimeout);
|
|
21
|
+
});
|
|
22
|
+
test('value is a positive integer', () => {
|
|
23
|
+
const { DB_BUSY_TIMEOUT_MS } = require('../hooks/lib/constants.cjs');
|
|
24
|
+
expect(Number.isInteger(DB_BUSY_TIMEOUT_MS)).toBe(true);
|
|
25
|
+
expect(DB_BUSY_TIMEOUT_MS).toBeGreaterThan(0);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=episode-kind-constant.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"episode-kind-constant.test.js","sourceRoot":"","sources":["../../tests/episode-kind-constant.test.ts"],"names":[],"mappings":";;AAAA,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;QACjD,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC1E,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QACzE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC3C,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QACjF,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;QACjF,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACvC,MAAM,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,MAAM,CAAC,kBAAkB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -25,11 +25,11 @@ afterEach(() => {
|
|
|
25
25
|
describe('session-focus episode injection', () => {
|
|
26
26
|
test('queryRecentEpisodes returns episodes ordered by created_at DESC', () => {
|
|
27
27
|
// Insert with explicit timestamps to guarantee order
|
|
28
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
28
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
29
29
|
VALUES ('ep-1', 'session', 'project', 'mindlore', 'First session', 'active', 'hook', '2026-04-13T10:00:00.000Z')`).run();
|
|
30
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
30
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
31
31
|
VALUES ('ep-2', 'decision', 'project', 'mindlore', 'Chose SQLite', 'active', 'diary', '2026-04-13T11:00:00.000Z')`).run();
|
|
32
|
-
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
32
|
+
db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
33
33
|
VALUES ('ep-3', 'learning', 'project', 'mindlore', 'Use ctx_execute_file', 'active', 'reflect', '2026-04-13T12:00:00.000Z')`).run();
|
|
34
34
|
const episodes = queryRecentEpisodes(db, { project: 'mindlore', limit: 3 });
|
|
35
35
|
expect(episodes).toHaveLength(3);
|
|
@@ -147,9 +147,9 @@ describe('episode stale filter', () => {
|
|
|
147
147
|
test('excludes episodes older than 7 days', () => {
|
|
148
148
|
const oldDate = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString();
|
|
149
149
|
const recentDate = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString();
|
|
150
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
150
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
151
151
|
VALUES ('ep-old', 'decision', 'project', 'mindlore', 'Old decision', 'active', 'diary', ?)`).run(oldDate);
|
|
152
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
152
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
153
153
|
VALUES ('ep-new', 'decision', 'project', 'mindlore', 'Recent decision', 'active', 'diary', ?)`).run(recentDate);
|
|
154
154
|
const payload = (0, session_payload_js_1.buildSessionPayload)({ db: migEnv.db, baseDir: migEnv.tmpDir, project: 'mindlore' });
|
|
155
155
|
const decisionsSection = payload.sections.find(s => s.label === 'Decisions');
|
|
@@ -159,7 +159,7 @@ describe('episode stale filter', () => {
|
|
|
159
159
|
});
|
|
160
160
|
test('includes episodes within 7 days', () => {
|
|
161
161
|
const recentDate = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString();
|
|
162
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
162
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
163
163
|
VALUES ('ep-r', 'learning', 'project', 'mindlore', 'Recent learning', 'active', 'reflect', ?)`).run(recentDate);
|
|
164
164
|
const payload = (0, session_payload_js_1.buildSessionPayload)({ db: migEnv.db, baseDir: migEnv.tmpDir, project: 'mindlore' });
|
|
165
165
|
const learningsSection = payload.sections.find(s => s.label === 'Learnings');
|
|
@@ -177,7 +177,7 @@ describe('episode inject dedup', () => {
|
|
|
177
177
|
});
|
|
178
178
|
test('excludes episodes already injected in this session', () => {
|
|
179
179
|
const recentDate = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString();
|
|
180
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
180
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
181
181
|
VALUES ('ep-d1', 'decision', 'project', 'mindlore', 'Already injected decision', 'active', 'diary', ?)`).run(recentDate);
|
|
182
182
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
183
183
|
const rowid = migEnv.db.prepare(`SELECT rowid FROM episodes WHERE id = 'ep-d1'`).get().rowid;
|
|
@@ -189,7 +189,7 @@ describe('episode inject dedup', () => {
|
|
|
189
189
|
});
|
|
190
190
|
test('logs newly injected episodes to episode_inject_log', () => {
|
|
191
191
|
const recentDate = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString();
|
|
192
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
192
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
193
193
|
VALUES ('ep-d2', 'learning', 'project', 'mindlore', 'New learning to log', 'active', 'reflect', ?)`).run(recentDate);
|
|
194
194
|
(0, session_payload_js_1.buildSessionPayload)({ db: migEnv.db, baseDir: migEnv.tmpDir, project: 'mindlore', tokenBudget: 2000, sessionId: 'session-xyz' });
|
|
195
195
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .all() returns unknown[]
|
|
@@ -198,7 +198,7 @@ describe('episode inject dedup', () => {
|
|
|
198
198
|
});
|
|
199
199
|
test('does not log when sessionId is not provided', () => {
|
|
200
200
|
const recentDate = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString();
|
|
201
|
-
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
201
|
+
migEnv.db.prepare(`INSERT INTO episodes (id, kind, scope, project, summary, status, source, created_at)
|
|
202
202
|
VALUES ('ep-d3', 'friction', 'project', 'mindlore', 'Friction point', 'active', 'diary', ?)`).run(recentDate);
|
|
203
203
|
(0, session_payload_js_1.buildSessionPayload)({ db: migEnv.db, baseDir: migEnv.tmpDir, project: 'mindlore' });
|
|
204
204
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .all() returns unknown[]
|
package/dist/tests/fts5.test.js
CHANGED
|
@@ -8,6 +8,7 @@ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const db_js_1 = require("./helpers/db.js");
|
|
10
10
|
const db_helpers_js_1 = require("../scripts/lib/db-helpers.js");
|
|
11
|
+
const constants_js_1 = require("../scripts/lib/constants.js");
|
|
11
12
|
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-mindlore-fts5');
|
|
12
13
|
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
13
14
|
beforeEach(() => {
|
|
@@ -33,9 +34,9 @@ describe('FTS5 Database', () => {
|
|
|
33
34
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'typescript-guide.md');
|
|
34
35
|
const content = '# TypeScript Guide\n\nTypeScript provides static typing for JavaScript applications.';
|
|
35
36
|
(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, dateCaptured: null });
|
|
36
|
-
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, rank FROM mindlore_fts
|
|
37
|
-
WHERE mindlore_fts MATCH ?
|
|
38
|
-
ORDER BY rank
|
|
37
|
+
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, rank FROM mindlore_fts
|
|
38
|
+
WHERE mindlore_fts MATCH ?
|
|
39
|
+
ORDER BY rank
|
|
39
40
|
LIMIT 3`, 'TypeScript');
|
|
40
41
|
expect(results).toHaveLength(1);
|
|
41
42
|
expect(results[0].path).toBe(testPath);
|
|
@@ -45,9 +46,9 @@ describe('FTS5 Database', () => {
|
|
|
45
46
|
const db = new better_sqlite3_1.default(DB_PATH);
|
|
46
47
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'python-guide.md');
|
|
47
48
|
(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, dateCaptured: null });
|
|
48
|
-
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path FROM mindlore_fts
|
|
49
|
-
WHERE mindlore_fts MATCH ?
|
|
50
|
-
ORDER BY rank
|
|
49
|
+
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path FROM mindlore_fts
|
|
50
|
+
WHERE mindlore_fts MATCH ?
|
|
51
|
+
ORDER BY rank
|
|
51
52
|
LIMIT 3`, 'Kubernetes');
|
|
52
53
|
expect(results).toHaveLength(0);
|
|
53
54
|
db.close();
|
|
@@ -56,9 +57,9 @@ describe('FTS5 Database', () => {
|
|
|
56
57
|
const db = new better_sqlite3_1.default(DB_PATH);
|
|
57
58
|
(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, dateCaptured: null });
|
|
58
59
|
(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, dateCaptured: null });
|
|
59
|
-
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, rank FROM mindlore_fts
|
|
60
|
-
WHERE mindlore_fts MATCH ?
|
|
61
|
-
ORDER BY rank
|
|
60
|
+
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, rank FROM mindlore_fts
|
|
61
|
+
WHERE mindlore_fts MATCH ?
|
|
62
|
+
ORDER BY rank
|
|
62
63
|
LIMIT 3`, 'hooks');
|
|
63
64
|
expect(results).toHaveLength(2);
|
|
64
65
|
const deepDive = results.find((r) => r.path.includes('deep-dive'));
|
|
@@ -70,9 +71,9 @@ describe('FTS5 Database', () => {
|
|
|
70
71
|
test('should index and search by tags column', () => {
|
|
71
72
|
const db = new better_sqlite3_1.default(DB_PATH);
|
|
72
73
|
(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, dateCaptured: null });
|
|
73
|
-
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, tags FROM mindlore_fts
|
|
74
|
-
WHERE tags MATCH ?
|
|
75
|
-
ORDER BY rank
|
|
74
|
+
const results = (0, db_helpers_js_1.dbAll)(db, `SELECT path, tags FROM mindlore_fts
|
|
75
|
+
WHERE tags MATCH ?
|
|
76
|
+
ORDER BY rank
|
|
76
77
|
LIMIT 3`, 'security');
|
|
77
78
|
expect(results).toHaveLength(1);
|
|
78
79
|
expect(results[0].tags).toBe('security, hooks, fts5');
|
|
@@ -109,7 +110,7 @@ describe('openDatabaseTs', () => {
|
|
|
109
110
|
const walMode = db.pragma('journal_mode', { simple: true });
|
|
110
111
|
expect(walMode).toBe('wal');
|
|
111
112
|
const timeout = db.pragma('busy_timeout', { simple: true });
|
|
112
|
-
expect(timeout).toBe(
|
|
113
|
+
expect(timeout).toBe(constants_js_1.DB_BUSY_TIMEOUT_MS);
|
|
113
114
|
db.close();
|
|
114
115
|
});
|
|
115
116
|
test('readonly should NOT set WAL', () => {
|
|
@@ -129,67 +130,7 @@ describe('openDatabase CJS', () => {
|
|
|
129
130
|
const walMode = db.pragma('journal_mode', { simple: true });
|
|
130
131
|
expect(walMode).toBe('wal');
|
|
131
132
|
const timeout = db.pragma('busy_timeout', { simple: true });
|
|
132
|
-
expect(timeout).toBe(
|
|
133
|
-
db.close();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
describe('Index with Embedding', () => {
|
|
137
|
-
test('should populate vec table when sqlite-vec is loaded', () => {
|
|
138
|
-
const { loadSqliteVec, ensureVecTable, hasVecTable: hasVec } = require('../scripts/lib/db-helpers.js');
|
|
139
|
-
const db = new better_sqlite3_1.default(DB_PATH);
|
|
140
|
-
const vecLoaded = loadSqliteVec(db);
|
|
141
|
-
if (!vecLoaded) {
|
|
142
|
-
console.log('sqlite-vec not available — skipping embed test');
|
|
143
|
-
db.close();
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
ensureVecTable(db);
|
|
147
|
-
expect(hasVec(db)).toBe(true);
|
|
148
|
-
// Insert a document to FTS
|
|
149
|
-
(0, db_js_1.insertFts)(db, {
|
|
150
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'embed-test.md'),
|
|
151
|
-
slug: 'embed-test',
|
|
152
|
-
description: 'Document for embedding test',
|
|
153
|
-
type: 'source',
|
|
154
|
-
category: 'sources',
|
|
155
|
-
title: 'Embed Test',
|
|
156
|
-
content: 'This document tests the embedding pipeline integration',
|
|
157
|
-
tags: 'test,embedding',
|
|
158
|
-
});
|
|
159
|
-
// Manually test vec insert with fake embedding
|
|
160
|
-
const fakeEmbedding = new Float32Array(384);
|
|
161
|
-
fakeEmbedding[0] = 1.0;
|
|
162
|
-
const buf = Buffer.from(fakeEmbedding.buffer);
|
|
163
|
-
db.prepare('INSERT INTO documents_vec (embedding, slug, created_at, model_name) VALUES (?, ?, ?, ?)').run(buf, 'embed-test', new Date().toISOString(), 'Xenova/multilingual-e5-small');
|
|
164
|
-
// Verify vec entry
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test: better-sqlite3 .get() returns unknown
|
|
166
|
-
const row = db.prepare('SELECT slug FROM documents_vec WHERE slug = ?').get('embed-test');
|
|
167
|
-
expect(row?.slug).toBe('embed-test');
|
|
168
|
-
db.close();
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
describe('Vec Table', () => {
|
|
172
|
-
test('should load sqlite-vec extension and create vec table', () => {
|
|
173
|
-
const { loadSqliteVec, ensureVecTable } = require('../scripts/lib/db-helpers.js');
|
|
174
|
-
const db = new better_sqlite3_1.default(DB_PATH);
|
|
175
|
-
const loaded = loadSqliteVec(db);
|
|
176
|
-
expect(loaded).toBe(true);
|
|
177
|
-
ensureVecTable(db);
|
|
178
|
-
// Verify table exists by inserting and querying
|
|
179
|
-
const testEmbedding = new Float32Array(384);
|
|
180
|
-
testEmbedding[0] = 1.0; // unit vector along first dimension
|
|
181
|
-
db.prepare('INSERT INTO documents_vec (embedding, slug, created_at, model_name) VALUES (?, ?, ?, ?)').run(Buffer.from(testEmbedding.buffer), 'test-slug', new Date().toISOString(), 'test-model');
|
|
182
|
-
// vec0 metadata columns are filterable in WHERE
|
|
183
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test: better-sqlite3 .get() returns unknown
|
|
184
|
-
const row = db.prepare('SELECT slug FROM documents_vec WHERE slug = ?').get('test-slug');
|
|
185
|
-
expect(row?.slug).toBe('test-slug');
|
|
186
|
-
db.close();
|
|
187
|
-
});
|
|
188
|
-
test('should return false when sqlite-vec is not available', () => {
|
|
189
|
-
const { ensureVecTable } = require('../scripts/lib/db-helpers.js');
|
|
190
|
-
const db = new better_sqlite3_1.default(DB_PATH);
|
|
191
|
-
// Without loadSqliteVec, ensureVecTable should handle gracefully
|
|
192
|
-
expect(() => ensureVecTable(db)).not.toThrow();
|
|
133
|
+
expect(timeout).toBe(constants_js_1.DB_BUSY_TIMEOUT_MS);
|
|
193
134
|
db.close();
|
|
194
135
|
});
|
|
195
136
|
});
|
|
@@ -202,13 +143,13 @@ describe('Timestamp columns', () => {
|
|
|
202
143
|
const hash1 = 'aaa111';
|
|
203
144
|
const now1 = '2026-04-19T10:00:00.000Z';
|
|
204
145
|
// Simulate first index: INSERT with created_at, no updated_at
|
|
205
|
-
const upsertHash = db.prepare(`
|
|
206
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at)
|
|
207
|
-
VALUES (?, ?, ?, datetime('now'))
|
|
208
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
209
|
-
content_hash = excluded.content_hash,
|
|
210
|
-
last_indexed = excluded.last_indexed,
|
|
211
|
-
updated_at = datetime('now')
|
|
146
|
+
const upsertHash = db.prepare(`
|
|
147
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at)
|
|
148
|
+
VALUES (?, ?, ?, datetime('now'))
|
|
149
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
150
|
+
content_hash = excluded.content_hash,
|
|
151
|
+
last_indexed = excluded.last_indexed,
|
|
152
|
+
updated_at = datetime('now')
|
|
212
153
|
`);
|
|
213
154
|
upsertHash.run(testPath, hash1, now1);
|
|
214
155
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
@@ -235,14 +176,14 @@ describe('Project scope on index', () => {
|
|
|
235
176
|
const hash = 'abc123';
|
|
236
177
|
const now = '2026-04-19T12:00:00.000Z';
|
|
237
178
|
const projectName = 'test-project';
|
|
238
|
-
const upsertHash = db.prepare(`
|
|
239
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope)
|
|
240
|
-
VALUES (?, ?, ?, datetime('now'), ?)
|
|
241
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
242
|
-
content_hash = excluded.content_hash,
|
|
243
|
-
last_indexed = excluded.last_indexed,
|
|
244
|
-
updated_at = datetime('now'),
|
|
245
|
-
project_scope = excluded.project_scope
|
|
179
|
+
const upsertHash = db.prepare(`
|
|
180
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope)
|
|
181
|
+
VALUES (?, ?, ?, datetime('now'), ?)
|
|
182
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
183
|
+
content_hash = excluded.content_hash,
|
|
184
|
+
last_indexed = excluded.last_indexed,
|
|
185
|
+
updated_at = datetime('now'),
|
|
186
|
+
project_scope = excluded.project_scope
|
|
246
187
|
`);
|
|
247
188
|
upsertHash.run(testPath, hash, now, projectName);
|
|
248
189
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
@@ -259,15 +200,15 @@ describe('Quality to importance mapping', () => {
|
|
|
259
200
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test helper returns Database
|
|
260
201
|
const db = createTestDbWithMigrations(DB_PATH);
|
|
261
202
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'test-importance-high.md');
|
|
262
|
-
const upsertHash = db.prepare(`
|
|
263
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
264
|
-
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
265
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
266
|
-
content_hash = excluded.content_hash,
|
|
267
|
-
last_indexed = excluded.last_indexed,
|
|
268
|
-
updated_at = datetime('now'),
|
|
269
|
-
project_scope = excluded.project_scope,
|
|
270
|
-
importance = excluded.importance
|
|
203
|
+
const upsertHash = db.prepare(`
|
|
204
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
205
|
+
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
206
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
207
|
+
content_hash = excluded.content_hash,
|
|
208
|
+
last_indexed = excluded.last_indexed,
|
|
209
|
+
updated_at = datetime('now'),
|
|
210
|
+
project_scope = excluded.project_scope,
|
|
211
|
+
importance = excluded.importance
|
|
271
212
|
`);
|
|
272
213
|
// Simulate indexer: quality 'high' -> importance 1.0
|
|
273
214
|
upsertHash.run(testPath, 'aaa', '2026-04-19T10:00:00.000Z', 'test', 1.0);
|
|
@@ -281,15 +222,15 @@ describe('Quality to importance mapping', () => {
|
|
|
281
222
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test helper returns Database
|
|
282
223
|
const db = createTestDbWithMigrations(DB_PATH);
|
|
283
224
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'test-importance-medium.md');
|
|
284
|
-
const upsertHash = db.prepare(`
|
|
285
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
286
|
-
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
287
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
288
|
-
content_hash = excluded.content_hash,
|
|
289
|
-
last_indexed = excluded.last_indexed,
|
|
290
|
-
updated_at = datetime('now'),
|
|
291
|
-
project_scope = excluded.project_scope,
|
|
292
|
-
importance = excluded.importance
|
|
225
|
+
const upsertHash = db.prepare(`
|
|
226
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
227
|
+
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
228
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
229
|
+
content_hash = excluded.content_hash,
|
|
230
|
+
last_indexed = excluded.last_indexed,
|
|
231
|
+
updated_at = datetime('now'),
|
|
232
|
+
project_scope = excluded.project_scope,
|
|
233
|
+
importance = excluded.importance
|
|
293
234
|
`);
|
|
294
235
|
upsertHash.run(testPath, 'bbb', '2026-04-19T10:00:00.000Z', 'test', 0.6);
|
|
295
236
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
@@ -302,15 +243,15 @@ describe('Quality to importance mapping', () => {
|
|
|
302
243
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test helper returns Database
|
|
303
244
|
const db = createTestDbWithMigrations(DB_PATH);
|
|
304
245
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'test-importance-low.md');
|
|
305
|
-
const upsertHash = db.prepare(`
|
|
306
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
307
|
-
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
308
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
309
|
-
content_hash = excluded.content_hash,
|
|
310
|
-
last_indexed = excluded.last_indexed,
|
|
311
|
-
updated_at = datetime('now'),
|
|
312
|
-
project_scope = excluded.project_scope,
|
|
313
|
-
importance = excluded.importance
|
|
246
|
+
const upsertHash = db.prepare(`
|
|
247
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
248
|
+
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
249
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
250
|
+
content_hash = excluded.content_hash,
|
|
251
|
+
last_indexed = excluded.last_indexed,
|
|
252
|
+
updated_at = datetime('now'),
|
|
253
|
+
project_scope = excluded.project_scope,
|
|
254
|
+
importance = excluded.importance
|
|
314
255
|
`);
|
|
315
256
|
upsertHash.run(testPath, 'ccc', '2026-04-19T10:00:00.000Z', 'test', 0.3);
|
|
316
257
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
@@ -323,15 +264,15 @@ describe('Quality to importance mapping', () => {
|
|
|
323
264
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- test helper returns Database
|
|
324
265
|
const db = createTestDbWithMigrations(DB_PATH);
|
|
325
266
|
const testPath = path_1.default.join(TEST_DIR, 'sources', 'test-no-quality.md');
|
|
326
|
-
const upsertHash = db.prepare(`
|
|
327
|
-
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
328
|
-
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
329
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
330
|
-
content_hash = excluded.content_hash,
|
|
331
|
-
last_indexed = excluded.last_indexed,
|
|
332
|
-
updated_at = datetime('now'),
|
|
333
|
-
project_scope = excluded.project_scope,
|
|
334
|
-
importance = excluded.importance
|
|
267
|
+
const upsertHash = db.prepare(`
|
|
268
|
+
INSERT INTO file_hashes (path, content_hash, last_indexed, created_at, project_scope, importance)
|
|
269
|
+
VALUES (?, ?, ?, datetime('now'), ?, ?)
|
|
270
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
271
|
+
content_hash = excluded.content_hash,
|
|
272
|
+
last_indexed = excluded.last_indexed,
|
|
273
|
+
updated_at = datetime('now'),
|
|
274
|
+
project_scope = excluded.project_scope,
|
|
275
|
+
importance = excluded.importance
|
|
335
276
|
`);
|
|
336
277
|
// quality undefined -> default 0.5
|
|
337
278
|
upsertHash.run(testPath, 'ddd', '2026-04-19T10:00:00.000Z', 'test', 0.5);
|