mindlore 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/SCHEMA.md +60 -4
- package/dist/scripts/init.d.ts +10 -0
- package/dist/scripts/init.d.ts.map +1 -0
- package/dist/scripts/init.js +375 -0
- package/dist/scripts/init.js.map +1 -0
- package/dist/scripts/lib/constants.d.ts +29 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -0
- package/dist/scripts/lib/constants.js +58 -0
- package/dist/scripts/lib/constants.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 +89 -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 +108 -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 +143 -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/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/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/helpers/db.d.ts +7 -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 +85 -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/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/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/hooks/lib/mindlore-common.cjs +36 -2
- package/hooks/mindlore-decision-detector.cjs +51 -0
- package/hooks/mindlore-fts5-sync.cjs +4 -18
- package/hooks/mindlore-index.cjs +4 -18
- package/hooks/mindlore-read-guard.cjs +62 -0
- package/hooks/mindlore-search.cjs +5 -18
- package/hooks/mindlore-session-end.cjs +74 -8
- package/package.json +19 -7
- package/plugin.json +26 -2
- package/skills/mindlore-decide/SKILL.md +71 -0
- package/skills/mindlore-ingest/SKILL.md +13 -2
- package/skills/mindlore-log/SKILL.md +79 -0
- package/skills/mindlore-query/SKILL.md +125 -0
- package/templates/SCHEMA.md +60 -4
- package/scripts/init.cjs +0 -450
- 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 -336
- package/scripts/uninstall.cjs +0 -186
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* mindlore uninstall — Remove Mindlore hooks, skills, and optionally project data.
|
|
5
|
+
*
|
|
6
|
+
* Usage: npx mindlore uninstall [--all]
|
|
7
|
+
*
|
|
8
|
+
* --all: also remove .mindlore/ project data (without flag, only hooks + skills)
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const constants_js_1 = require("./lib/constants.js");
|
|
17
|
+
function log(msg) {
|
|
18
|
+
console.log(` ${msg}`);
|
|
19
|
+
}
|
|
20
|
+
// ── Remove hooks from settings.json ────────────────────────────────────
|
|
21
|
+
function removeHooks() {
|
|
22
|
+
const settingsPath = path_1.default.join((0, constants_js_1.homedir)(), '.claude', 'settings.json');
|
|
23
|
+
if (!fs_1.default.existsSync(settingsPath)) {
|
|
24
|
+
log('No settings.json found, skipping hooks');
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
let settings;
|
|
28
|
+
try {
|
|
29
|
+
settings = JSON.parse(fs_1.default.readFileSync(settingsPath, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
catch (_err) {
|
|
32
|
+
log('Could not parse settings.json, skipping hooks');
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (!settings.hooks)
|
|
36
|
+
return 0;
|
|
37
|
+
let removed = 0;
|
|
38
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
39
|
+
const entries = settings.hooks[event];
|
|
40
|
+
if (!Array.isArray(entries))
|
|
41
|
+
continue;
|
|
42
|
+
const filtered = entries.filter((entry) => {
|
|
43
|
+
const hooks = entry.hooks ?? [];
|
|
44
|
+
const hasMindlore = hooks.some((h) => (h.command ?? '').includes('mindlore-'));
|
|
45
|
+
const flatMindlore = (entry.command ?? '').includes('mindlore-');
|
|
46
|
+
if (hasMindlore || flatMindlore) {
|
|
47
|
+
removed++;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
52
|
+
settings.hooks[event] = filtered;
|
|
53
|
+
if (settings.hooks[event].length === 0) {
|
|
54
|
+
delete settings.hooks[event];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (removed > 0) {
|
|
58
|
+
fs_1.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
59
|
+
}
|
|
60
|
+
return removed;
|
|
61
|
+
}
|
|
62
|
+
// ── Remove skills from ~/.claude/skills/ ───────────────────────────────
|
|
63
|
+
function removeSkills() {
|
|
64
|
+
const skillsDir = path_1.default.join((0, constants_js_1.homedir)(), '.claude', 'skills');
|
|
65
|
+
if (!fs_1.default.existsSync(skillsDir))
|
|
66
|
+
return 0;
|
|
67
|
+
const mindloreSkills = fs_1.default
|
|
68
|
+
.readdirSync(skillsDir)
|
|
69
|
+
.filter((d) => d.startsWith('mindlore-'));
|
|
70
|
+
let removed = 0;
|
|
71
|
+
for (const skill of mindloreSkills) {
|
|
72
|
+
const skillPath = path_1.default.join(skillsDir, skill);
|
|
73
|
+
fs_1.default.rmSync(skillPath, { recursive: true, force: true });
|
|
74
|
+
removed++;
|
|
75
|
+
}
|
|
76
|
+
return removed;
|
|
77
|
+
}
|
|
78
|
+
// ── Remove SCHEMA.md from projectDocFiles ──────────────────────────────
|
|
79
|
+
function removeFromProjectDocs() {
|
|
80
|
+
const projectSettingsPath = path_1.default.join(process.cwd(), '.claude', 'settings.json');
|
|
81
|
+
if (!fs_1.default.existsSync(projectSettingsPath))
|
|
82
|
+
return false;
|
|
83
|
+
let settings;
|
|
84
|
+
try {
|
|
85
|
+
settings = JSON.parse(fs_1.default.readFileSync(projectSettingsPath, 'utf8'));
|
|
86
|
+
}
|
|
87
|
+
catch (_err) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (!settings.projectDocFiles)
|
|
91
|
+
return false;
|
|
92
|
+
const before = settings.projectDocFiles.length;
|
|
93
|
+
settings.projectDocFiles = settings.projectDocFiles.filter((p) => !p.includes('mindlore'));
|
|
94
|
+
if (settings.projectDocFiles.length < before) {
|
|
95
|
+
fs_1.default.writeFileSync(projectSettingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
// ── Remove .mindlore/ project data ─────────────────────────────────────
|
|
101
|
+
function removeProjectData() {
|
|
102
|
+
const mindloreDir = path_1.default.join(process.cwd(), '.mindlore');
|
|
103
|
+
if (!fs_1.default.existsSync(mindloreDir)) {
|
|
104
|
+
log('No .mindlore/ directory in current project');
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
fs_1.default.rmSync(mindloreDir, { recursive: true, force: true });
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
// ── Main ───────────────────────────────────────────────────────────────
|
|
111
|
+
function main() {
|
|
112
|
+
const args = process.argv.slice(2);
|
|
113
|
+
const removeAll = args.includes('--all');
|
|
114
|
+
console.log('\n Mindlore — Uninstall\n');
|
|
115
|
+
// Hooks
|
|
116
|
+
const hooksRemoved = removeHooks();
|
|
117
|
+
log(hooksRemoved > 0
|
|
118
|
+
? `Removed ${hooksRemoved} hooks from ~/.claude/settings.json`
|
|
119
|
+
: 'No hooks found');
|
|
120
|
+
// Skills
|
|
121
|
+
const skillsRemoved = removeSkills();
|
|
122
|
+
log(skillsRemoved > 0
|
|
123
|
+
? `Removed ${skillsRemoved} skills from ~/.claude/skills/`
|
|
124
|
+
: 'No skills found');
|
|
125
|
+
// Project doc files
|
|
126
|
+
const docsRemoved = removeFromProjectDocs();
|
|
127
|
+
log(docsRemoved
|
|
128
|
+
? 'Removed SCHEMA.md from project settings'
|
|
129
|
+
: 'No project doc references found');
|
|
130
|
+
// Project data (only with --all)
|
|
131
|
+
if (removeAll) {
|
|
132
|
+
const dataRemoved = removeProjectData();
|
|
133
|
+
log(dataRemoved
|
|
134
|
+
? 'Removed .mindlore/ project data'
|
|
135
|
+
: 'No .mindlore/ directory found');
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
log('.mindlore/ project data kept (use --all to remove)');
|
|
139
|
+
}
|
|
140
|
+
console.log('\n Done! Mindlore has been uninstalled.\n');
|
|
141
|
+
}
|
|
142
|
+
main();
|
|
143
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../scripts/uninstall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compounding test — v0.2 integration test
|
|
3
|
+
*
|
|
4
|
+
* Tests the full cycle: query → writeback → reindex → next query finds it.
|
|
5
|
+
* Skipped in v0.1 (configured in jest.config.cjs testPathIgnorePatterns).
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=compounding.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compounding.test.d.ts","sourceRoot":"","sources":["../../tests/compounding.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Compounding test — v0.2 integration test
|
|
4
|
+
*
|
|
5
|
+
* Tests the full cycle: query → writeback → reindex → next query finds it.
|
|
6
|
+
* Skipped in v0.1 (configured in jest.config.cjs testPathIgnorePatterns).
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const db_js_1 = require("./helpers/db.js");
|
|
15
|
+
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-mindlore-compounding');
|
|
16
|
+
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources', 'insights']);
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
22
|
+
});
|
|
23
|
+
describe('Knowledge Compounding', () => {
|
|
24
|
+
test('writeback → reindex → query should find the new content', () => {
|
|
25
|
+
const db = (0, db_js_1.createTestDb)(DB_PATH);
|
|
26
|
+
// Step 1: Index an existing source
|
|
27
|
+
const sourcePath = path_1.default.join(TEST_DIR, 'sources', 'react-hooks.md');
|
|
28
|
+
const sourceContent = '---\nslug: react-hooks\ntype: source\n---\n# React Hooks\n\nUseEffect cleanup patterns.';
|
|
29
|
+
fs_1.default.writeFileSync(sourcePath, sourceContent);
|
|
30
|
+
(0, db_js_1.insertFts)(db, sourcePath, 'react-hooks', 'UseEffect cleanup patterns', 'source', 'sources', 'React Hooks', sourceContent, '', null);
|
|
31
|
+
db.prepare('INSERT INTO file_hashes (path, content_hash, last_indexed) VALUES (?, ?, ?)').run(sourcePath, (0, db_js_1.sha256)(sourceContent), new Date().toISOString());
|
|
32
|
+
// Step 2: Simulate query → writeback (agent creates an insight)
|
|
33
|
+
const insightPath = path_1.default.join(TEST_DIR, 'insights', 'react-cleanup.md');
|
|
34
|
+
const insightContent = '---\nslug: react-cleanup\ntype: insight\n---\n# React Cleanup Pattern\n\nAlways return cleanup function from useEffect to avoid memory leaks.';
|
|
35
|
+
fs_1.default.writeFileSync(insightPath, insightContent);
|
|
36
|
+
// Step 3: Reindex (simulates the hook)
|
|
37
|
+
(0, db_js_1.insertFts)(db, insightPath, 'react-cleanup', 'Avoid memory leaks with useEffect cleanup', 'insight', 'insights', 'React Cleanup Pattern', insightContent, '', null);
|
|
38
|
+
db.prepare('INSERT INTO file_hashes (path, content_hash, last_indexed) VALUES (?, ?, ?)').run(insightPath, (0, db_js_1.sha256)(insightContent), new Date().toISOString());
|
|
39
|
+
// Step 4: Next query should find the writeback content
|
|
40
|
+
const results = db
|
|
41
|
+
.prepare(`SELECT path FROM mindlore_fts
|
|
42
|
+
WHERE mindlore_fts MATCH ?
|
|
43
|
+
ORDER BY rank
|
|
44
|
+
LIMIT 3`)
|
|
45
|
+
.all('memory leaks cleanup');
|
|
46
|
+
expect(results.length).toBeGreaterThan(0);
|
|
47
|
+
expect(results.some((r) => r.path.includes('react-cleanup'))).toBe(true);
|
|
48
|
+
db.close();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=compounding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compounding.test.js","sourceRoot":"","sources":["../../tests/compounding.test.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AAEH,4CAAoB;AACpB,gDAAwB;AACxB,2CAAiG;AAEjG,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,4BAA4B,CAAC,CAAC;AAC1E,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEnD,UAAU,CAAC,GAAG,EAAE;IACd,IAAA,oBAAY,EAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,IAAA,uBAAe,EAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAMH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACnE,MAAM,EAAE,GAAG,IAAA,oBAAY,EAAC,OAAO,CAAC,CAAC;QAEjC,mCAAmC;QACnC,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACpE,MAAM,aAAa,GAAG,yFAAyF,CAAC;QAChH,YAAE,CAAC,aAAa,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAE5C,IAAA,iBAAS,EAAC,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,4BAA4B,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACpI,EAAE,CAAC,OAAO,CACR,6EAA6E,CAC9E,CAAC,GAAG,CAAC,UAAU,EAAE,IAAA,cAAM,EAAC,aAAa,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAEnE,gEAAgE;QAChE,MAAM,WAAW,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;QACxE,MAAM,cAAc,GAClB,+IAA+I,CAAC;QAClJ,YAAE,CAAC,aAAa,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAE9C,uCAAuC;QACvC,IAAA,iBAAS,EAAC,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,2CAA2C,EAAE,SAAS,EAAE,UAAU,EAAE,uBAAuB,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACnK,EAAE,CAAC,OAAO,CACR,6EAA6E,CAC9E,CAAC,GAAG,CAAC,WAAW,EAAE,IAAA,cAAM,EAAC,cAAc,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAErE,uDAAuD;QACvD,MAAM,OAAO,GAAG,EAAE;aACf,OAAO,CACN;;;iBAGS,CACV;aACA,GAAG,CAAC,sBAAsB,CAAiB,CAAC;QAE/C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEzE,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.test.d.ts","sourceRoot":"","sources":["../../tests/decision.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
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 fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const db_js_1 = require("./helpers/db.js");
|
|
10
|
+
const PROJECT_DIR = path_1.default.join(__dirname, '..', '.test-project-decision');
|
|
11
|
+
const MINDLORE_DIR = path_1.default.join(PROJECT_DIR, '.mindlore');
|
|
12
|
+
const HOOK_PATH = path_1.default.join(__dirname, '..', 'hooks', 'mindlore-decision-detector.cjs');
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
(0, db_js_1.setupTestDir)(MINDLORE_DIR, ['decisions', 'diary']);
|
|
15
|
+
fs_1.default.writeFileSync(path_1.default.join(MINDLORE_DIR, 'INDEX.md'), '# Index\n', 'utf8');
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
(0, db_js_1.teardownTestDir)(PROJECT_DIR);
|
|
19
|
+
});
|
|
20
|
+
function runDetector(input) {
|
|
21
|
+
try {
|
|
22
|
+
const result = (0, child_process_1.execSync)(`node "${HOOK_PATH}"`, {
|
|
23
|
+
input,
|
|
24
|
+
encoding: 'utf8',
|
|
25
|
+
timeout: 5000,
|
|
26
|
+
cwd: PROJECT_DIR,
|
|
27
|
+
env: { ...process.env },
|
|
28
|
+
});
|
|
29
|
+
return result.trim();
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
const e = err;
|
|
33
|
+
return (e.stdout ?? '').trim();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
describe('Decision Detector Hook', () => {
|
|
37
|
+
test('should detect Turkish decision signal', () => {
|
|
38
|
+
const output = runDetector('FTS5 kullanmaya karar verdik, vector search ertelenecek');
|
|
39
|
+
expect(output).toContain('Karar sinyali');
|
|
40
|
+
expect(output).toContain('karar verdik');
|
|
41
|
+
});
|
|
42
|
+
test('should detect English decision signal', () => {
|
|
43
|
+
const output = runDetector('We decided to use SQLite instead of PostgreSQL');
|
|
44
|
+
expect(output).toContain('Karar sinyali');
|
|
45
|
+
expect(output).toContain('decided');
|
|
46
|
+
});
|
|
47
|
+
test('should not trigger on normal text', () => {
|
|
48
|
+
const output = runDetector('Bu dosyayı oku ve bana özetle');
|
|
49
|
+
expect(output).toBe('');
|
|
50
|
+
});
|
|
51
|
+
test('should not trigger on short input', () => {
|
|
52
|
+
const output = runDetector('merhaba');
|
|
53
|
+
expect(output).toBe('');
|
|
54
|
+
});
|
|
55
|
+
test('should handle JSON input format', () => {
|
|
56
|
+
const input = JSON.stringify({ prompt: "Let's go with option B for the API design" });
|
|
57
|
+
const output = runDetector(input);
|
|
58
|
+
expect(output).toContain('Karar sinyali');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=decision.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.test.js","sourceRoot":"","sources":["../../tests/decision.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.test.d.ts","sourceRoot":"","sources":["../../tests/dedup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
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-dedup');
|
|
10
|
+
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
(0, db_js_1.setupTestDir)(TEST_DIR);
|
|
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('Content-Hash Dedup', () => {
|
|
20
|
+
test('should index file and store hash', () => {
|
|
21
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
22
|
+
const content = '# Test\n\nSome content here.';
|
|
23
|
+
const hash = (0, db_js_1.sha256)(content);
|
|
24
|
+
const filePath = path_1.default.join(TEST_DIR, 'test.md');
|
|
25
|
+
(0, db_js_1.insertFts)(db, filePath, 'test-doc', 'Some content here', 'source', 'sources', 'Test', content, '', null);
|
|
26
|
+
db.prepare('INSERT INTO file_hashes (path, content_hash, last_indexed) VALUES (?, ?, ?)').run(filePath, hash, new Date().toISOString());
|
|
27
|
+
const result = db
|
|
28
|
+
.prepare('SELECT content_hash FROM file_hashes WHERE path = ?')
|
|
29
|
+
.get(filePath);
|
|
30
|
+
expect(result.content_hash).toBe(hash);
|
|
31
|
+
db.close();
|
|
32
|
+
});
|
|
33
|
+
test('should skip re-index when content unchanged', () => {
|
|
34
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
35
|
+
const content = '# Unchanged\n\nThis content does not change.';
|
|
36
|
+
const hash = (0, db_js_1.sha256)(content);
|
|
37
|
+
const filePath = path_1.default.join(TEST_DIR, 'unchanged.md');
|
|
38
|
+
(0, db_js_1.insertFts)(db, filePath, 'unchanged-doc', 'This content does not change', 'source', 'sources', 'Unchanged', content, '', null);
|
|
39
|
+
db.prepare('INSERT INTO file_hashes (path, content_hash, last_indexed) VALUES (?, ?, ?)').run(filePath, hash, '2026-01-01T00:00:00Z');
|
|
40
|
+
const existing = db
|
|
41
|
+
.prepare('SELECT content_hash FROM file_hashes WHERE path = ?')
|
|
42
|
+
.get(filePath);
|
|
43
|
+
const newHash = (0, db_js_1.sha256)(content);
|
|
44
|
+
expect(existing.content_hash).toBe(newHash);
|
|
45
|
+
const count = db
|
|
46
|
+
.prepare('SELECT count(*) as cnt FROM mindlore_fts WHERE path = ?')
|
|
47
|
+
.get(filePath);
|
|
48
|
+
expect(count.cnt).toBe(1);
|
|
49
|
+
db.close();
|
|
50
|
+
});
|
|
51
|
+
test('should re-index when content changes', () => {
|
|
52
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
53
|
+
const original = '# Original\n\nFirst version.';
|
|
54
|
+
const modified = '# Modified\n\nSecond version with changes.';
|
|
55
|
+
const filePath = path_1.default.join(TEST_DIR, 'changing.md');
|
|
56
|
+
const originalHash = (0, db_js_1.sha256)(original);
|
|
57
|
+
(0, db_js_1.insertFts)(db, filePath, 'changing-doc', 'First version', 'source', 'sources', 'Original', original, '', null);
|
|
58
|
+
db.prepare('INSERT INTO file_hashes (path, content_hash, last_indexed) VALUES (?, ?, ?)').run(filePath, originalHash, '2026-01-01T00:00:00Z');
|
|
59
|
+
const modifiedHash = (0, db_js_1.sha256)(modified);
|
|
60
|
+
const existing = db
|
|
61
|
+
.prepare('SELECT content_hash FROM file_hashes WHERE path = ?')
|
|
62
|
+
.get(filePath);
|
|
63
|
+
expect(existing.content_hash).not.toBe(modifiedHash);
|
|
64
|
+
db.prepare('DELETE FROM mindlore_fts WHERE path = ?').run(filePath);
|
|
65
|
+
(0, db_js_1.insertFts)(db, filePath, 'changing-doc', 'Second version with changes', 'source', 'sources', 'Modified', modified, '', null);
|
|
66
|
+
db.prepare('UPDATE file_hashes SET content_hash = ?, last_indexed = ? WHERE path = ?').run(modifiedHash, new Date().toISOString(), filePath);
|
|
67
|
+
const results = db
|
|
68
|
+
.prepare('SELECT path FROM mindlore_fts WHERE mindlore_fts MATCH ?')
|
|
69
|
+
.all('changes');
|
|
70
|
+
expect(results).toHaveLength(1);
|
|
71
|
+
db.close();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=dedup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.test.js","sourceRoot":"","sources":["../../tests/dedup.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, testPath, 'test-source', 'TypeScript and Node.js performance', 'source', 'sources', 'Test Source', testContent, '', 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, testPath, 'typescript-guide', 'TypeScript static typing for JavaScript', 'source', 'sources', 'TypeScript Guide', content, '', 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, testPath, 'python-guide', 'Python for data science', 'source', 'sources', 'Python Guide', '# Python Guide\n\nPython is great for data science.', '', 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_1.default.join(TEST_DIR, 'sources', 'hooks-overview.md'), 'hooks-overview', 'Hooks lifecycle callbacks overview', 'source', 'sources', 'Hooks Overview', '# Hooks Overview\n\nHooks are lifecycle callbacks.', '', null);
|
|
60
|
+
(0, db_js_1.insertFts)(db, path_1.default.join(TEST_DIR, 'sources', 'hooks-deep-dive.md'), 'hooks-deep-dive', 'Deep dive into hooks patterns', 'source', 'sources', 'Hooks Deep Dive', '# Hooks Deep Dive\n\nHooks hooks hooks. PreToolUse hooks, PostToolUse hooks, SessionStart hooks.', '', 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_1.default.join(TEST_DIR, 'sources', 'tagged-doc.md'), 'tagged-doc', 'A doc with tags', 'source', 'sources', 'Tagged Doc', '# Tagged\n\nContent here.', 'security, hooks, fts5', 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_1.default.join(TEST_DIR, 'sources', 'no-quality.md'), 'no-quality', 'No quality set', 'source', 'sources', 'No Quality', '# Test\n\nContent.', '', 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,7 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
export declare function sha256(content: string): string;
|
|
3
|
+
export declare function createTestDb(dbPath: string): Database.Database;
|
|
4
|
+
export declare function insertFts(db: Database.Database, filePath: string, slug: string, description: string, type: string, category: string, title: string, content: string, tags: string, quality: string | null): void;
|
|
5
|
+
export declare function setupTestDir(testDir: string, subdirs?: string[]): void;
|
|
6
|
+
export declare function teardownTestDir(testDir: string): void;
|
|
7
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../tests/helpers/db.ts"],"names":[],"mappings":"AAGA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAStC,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAY9D;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,IAAI,CAYN;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAMtE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAErD"}
|