mindlore 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/dist/scripts/fetch-raw.d.ts +2 -0
- package/dist/scripts/fetch-raw.d.ts.map +1 -0
- package/dist/scripts/fetch-raw.js +124 -0
- package/dist/scripts/fetch-raw.js.map +1 -0
- package/dist/scripts/init.js +45 -3
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +13 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +24 -4
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/db-helpers.d.ts +12 -2
- package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
- package/dist/scripts/lib/db-helpers.js +36 -0
- package/dist/scripts/lib/db-helpers.js.map +1 -1
- package/dist/scripts/lib/hybrid-search.d.ts +0 -2
- package/dist/scripts/lib/hybrid-search.d.ts.map +1 -1
- package/dist/scripts/lib/hybrid-search.js +7 -1
- package/dist/scripts/lib/hybrid-search.js.map +1 -1
- package/dist/scripts/lib/migrations-v051.d.ts +3 -0
- package/dist/scripts/lib/migrations-v051.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v051.js +24 -0
- package/dist/scripts/lib/migrations-v051.js.map +1 -0
- package/dist/scripts/lib/migrations-v052.d.ts +3 -0
- package/dist/scripts/lib/migrations-v052.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v052.js +23 -0
- package/dist/scripts/lib/migrations-v052.js.map +1 -0
- package/dist/scripts/lib/migrations.d.ts +1 -0
- package/dist/scripts/lib/migrations.d.ts.map +1 -1
- package/dist/scripts/lib/migrations.js +3 -1
- package/dist/scripts/lib/migrations.js.map +1 -1
- package/dist/scripts/lib/privacy-filter.d.ts +3 -0
- package/dist/scripts/lib/privacy-filter.d.ts.map +1 -0
- package/dist/scripts/lib/privacy-filter.js +28 -0
- package/dist/scripts/lib/privacy-filter.js.map +1 -0
- package/dist/scripts/lib/similarity.d.ts +12 -0
- package/dist/scripts/lib/similarity.d.ts.map +1 -0
- package/dist/scripts/lib/similarity.js +64 -0
- package/dist/scripts/lib/similarity.js.map +1 -0
- package/dist/scripts/lib/skeleton.d.ts +2 -0
- package/dist/scripts/lib/skeleton.d.ts.map +1 -0
- package/dist/scripts/lib/skeleton.js +99 -0
- package/dist/scripts/lib/skeleton.js.map +1 -0
- package/dist/scripts/lib/skill-memory.d.ts +13 -0
- package/dist/scripts/lib/skill-memory.d.ts.map +1 -0
- package/dist/scripts/lib/skill-memory.js +94 -0
- package/dist/scripts/lib/skill-memory.js.map +1 -0
- package/dist/scripts/mindlore-fts5-index.js +18 -3
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts +1 -1
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +117 -96
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/scripts/quality-populate.js +8 -4
- package/dist/scripts/quality-populate.js.map +1 -1
- package/dist/tests/catch-up.test.d.ts +2 -0
- package/dist/tests/catch-up.test.d.ts.map +1 -0
- package/dist/tests/catch-up.test.js +88 -0
- package/dist/tests/catch-up.test.js.map +1 -0
- package/dist/tests/cc-memory-sync.test.d.ts +2 -0
- package/dist/tests/cc-memory-sync.test.d.ts.map +1 -0
- package/dist/tests/cc-memory-sync.test.js +121 -0
- package/dist/tests/cc-memory-sync.test.js.map +1 -0
- package/dist/tests/episode-file.test.d.ts +2 -0
- package/dist/tests/episode-file.test.d.ts.map +1 -0
- package/dist/tests/episode-file.test.js +82 -0
- package/dist/tests/episode-file.test.js.map +1 -0
- package/dist/tests/fetch-raw.test.d.ts +2 -0
- package/dist/tests/fetch-raw.test.d.ts.map +1 -0
- package/dist/tests/fetch-raw.test.js +43 -0
- package/dist/tests/fetch-raw.test.js.map +1 -0
- package/dist/tests/helpers/db.d.ts +1 -0
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +10 -0
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/hook-logging.test.d.ts +2 -0
- package/dist/tests/hook-logging.test.d.ts.map +1 -0
- package/dist/tests/hook-logging.test.js +108 -0
- package/dist/tests/hook-logging.test.js.map +1 -0
- package/dist/tests/index-cli-embed.test.d.ts +7 -0
- package/dist/tests/index-cli-embed.test.d.ts.map +1 -0
- package/dist/tests/index-cli-embed.test.js +128 -0
- package/dist/tests/index-cli-embed.test.js.map +1 -0
- package/dist/tests/privacy-filter.test.d.ts +2 -0
- package/dist/tests/privacy-filter.test.d.ts.map +1 -0
- package/dist/tests/privacy-filter.test.js +56 -0
- package/dist/tests/privacy-filter.test.js.map +1 -0
- package/dist/tests/resolve-hook-common.test.d.ts +2 -0
- package/dist/tests/resolve-hook-common.test.d.ts.map +1 -0
- package/dist/tests/resolve-hook-common.test.js +30 -0
- package/dist/tests/resolve-hook-common.test.js.map +1 -0
- package/dist/tests/schema-version.test.js +28 -0
- package/dist/tests/schema-version.test.js.map +1 -1
- package/dist/tests/search-cli-hybrid.test.d.ts +6 -0
- package/dist/tests/search-cli-hybrid.test.d.ts.map +1 -0
- package/dist/tests/search-cli-hybrid.test.js +103 -0
- package/dist/tests/search-cli-hybrid.test.js.map +1 -0
- package/dist/tests/search-hook.test.js +33 -0
- package/dist/tests/search-hook.test.js.map +1 -1
- package/dist/tests/search-offload.test.d.ts +2 -0
- package/dist/tests/search-offload.test.d.ts.map +1 -0
- package/dist/tests/search-offload.test.js +34 -0
- package/dist/tests/search-offload.test.js.map +1 -0
- package/dist/tests/similarity.test.d.ts +2 -0
- package/dist/tests/similarity.test.d.ts.map +1 -0
- package/dist/tests/similarity.test.js +61 -0
- package/dist/tests/similarity.test.js.map +1 -0
- package/dist/tests/skeleton.test.d.ts +2 -0
- package/dist/tests/skeleton.test.d.ts.map +1 -0
- package/dist/tests/skeleton.test.js +116 -0
- package/dist/tests/skeleton.test.js.map +1 -0
- package/dist/tests/skill-memory-api.test.d.ts +2 -0
- package/dist/tests/skill-memory-api.test.d.ts.map +1 -0
- package/dist/tests/skill-memory-api.test.js +62 -0
- package/dist/tests/skill-memory-api.test.js.map +1 -0
- package/dist/tests/skill-memory.test.d.ts +2 -0
- package/dist/tests/skill-memory.test.d.ts.map +1 -0
- package/dist/tests/skill-memory.test.js +67 -0
- package/dist/tests/skill-memory.test.js.map +1 -0
- package/dist/tests/token-budget.test.d.ts +2 -0
- package/dist/tests/token-budget.test.d.ts.map +1 -0
- package/dist/tests/token-budget.test.js +32 -0
- package/dist/tests/token-budget.test.js.map +1 -0
- package/dist/tests/wiki-lint.test.d.ts +2 -0
- package/dist/tests/wiki-lint.test.d.ts.map +1 -0
- package/dist/tests/wiki-lint.test.js +47 -0
- package/dist/tests/wiki-lint.test.js.map +1 -0
- package/hooks/lib/mindlore-common.cjs +109 -2
- package/hooks/mindlore-cwd-changed.cjs +2 -2
- package/hooks/mindlore-decision-detector.cjs +2 -2
- package/hooks/mindlore-dont-repeat.cjs +2 -2
- package/hooks/mindlore-fts5-sync.cjs +2 -2
- package/hooks/mindlore-index.cjs +141 -3
- package/hooks/mindlore-model-router.cjs +2 -2
- package/hooks/mindlore-post-compact.cjs +2 -2
- package/hooks/mindlore-post-read.cjs +2 -2
- package/hooks/mindlore-pre-compact.cjs +2 -2
- package/hooks/mindlore-read-guard.cjs +15 -3
- package/hooks/mindlore-research-guard.cjs +2 -2
- package/hooks/mindlore-search.cjs +69 -41
- package/hooks/mindlore-session-end.cjs +129 -39
- package/hooks/mindlore-session-focus.cjs +24 -3
- package/package.json +6 -5
- package/plugin.json +29 -2
- package/skills/mindlore-diary/SKILL.md +76 -0
- package/skills/mindlore-ingest/SKILL.md +48 -50
- package/skills/mindlore-log/SKILL.md +3 -143
- package/skills/mindlore-reflect/SKILL.md +104 -0
- package/templates/config.json +6 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-memory-api.test.js","sourceRoot":"","sources":["../../tests/skill-memory-api.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-memory.test.d.ts","sourceRoot":"","sources":["../../tests/skill-memory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
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 better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const schema_version_1 = require("../scripts/lib/schema-version");
|
|
11
|
+
const migrations_v052_1 = require("../scripts/lib/migrations-v052");
|
|
12
|
+
describe('skill_memory table', () => {
|
|
13
|
+
let db;
|
|
14
|
+
let tmpDir;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'mindlore-skillmem-'));
|
|
17
|
+
const dbPath = path_1.default.join(tmpDir, 'test.db');
|
|
18
|
+
db = new better_sqlite3_1.default(dbPath);
|
|
19
|
+
db.pragma('journal_mode = WAL');
|
|
20
|
+
(0, schema_version_1.ensureSchemaTable)(db);
|
|
21
|
+
(0, schema_version_1.runMigrations)(db, migrations_v052_1.V052_MIGRATIONS);
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
db.close();
|
|
25
|
+
fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
it('creates skill_memory table', () => {
|
|
28
|
+
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='skill_memory'").all();
|
|
29
|
+
expect(tables).toHaveLength(1);
|
|
30
|
+
});
|
|
31
|
+
it('inserts and retrieves skill memory', () => {
|
|
32
|
+
db.prepare(`INSERT INTO skill_memory (skill_name, key, value, updated_at)
|
|
33
|
+
VALUES (?, ?, ?, ?)`).run('mindlore-ingest', 'last_ingest_urls', '["https://example.com"]', new Date().toISOString());
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
35
|
+
const row = db.prepare('SELECT * FROM skill_memory WHERE skill_name = ? AND key = ?').get('mindlore-ingest', 'last_ingest_urls');
|
|
36
|
+
expect(row).toBeDefined();
|
|
37
|
+
expect(row.value).toBe('["https://example.com"]');
|
|
38
|
+
expect(row.access_count).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
it('enforces UNIQUE(skill_name, key) constraint', () => {
|
|
41
|
+
const insert = db.prepare(`INSERT INTO skill_memory (skill_name, key, value, updated_at)
|
|
42
|
+
VALUES (?, ?, ?, ?)`);
|
|
43
|
+
insert.run('mindlore-query', 'log', '[]', new Date().toISOString());
|
|
44
|
+
expect(() => {
|
|
45
|
+
insert.run('mindlore-query', 'log', '["x"]', new Date().toISOString());
|
|
46
|
+
}).toThrow();
|
|
47
|
+
});
|
|
48
|
+
it('upserts with ON CONFLICT', () => {
|
|
49
|
+
const upsert = db.prepare(`INSERT INTO skill_memory (skill_name, key, value, updated_at)
|
|
50
|
+
VALUES (?, ?, ?, ?)
|
|
51
|
+
ON CONFLICT(skill_name, key) DO UPDATE SET
|
|
52
|
+
value = excluded.value,
|
|
53
|
+
updated_at = excluded.updated_at,
|
|
54
|
+
access_count = access_count + 1`);
|
|
55
|
+
const now = new Date().toISOString();
|
|
56
|
+
upsert.run('mindlore-diary', 'last_date', '"2026-04-18"', now);
|
|
57
|
+
upsert.run('mindlore-diary', 'last_date', '"2026-04-19"', now);
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- better-sqlite3 .get() returns unknown
|
|
59
|
+
const row = db.prepare('SELECT * FROM skill_memory WHERE skill_name = ? AND key = ?').get('mindlore-diary', 'last_date');
|
|
60
|
+
expect(row.value).toBe('"2026-04-19"');
|
|
61
|
+
expect(row.access_count).toBe(1);
|
|
62
|
+
});
|
|
63
|
+
it('migration is idempotent', () => {
|
|
64
|
+
expect(() => (0, schema_version_1.runMigrations)(db, migrations_v052_1.V052_MIGRATIONS)).not.toThrow();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=skill-memory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-memory.test.js","sourceRoot":"","sources":["../../tests/skill-memory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-budget.test.d.ts","sourceRoot":"","sources":["../../tests/token-budget.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const constants_js_1 = require("../scripts/lib/constants.js");
|
|
4
|
+
describe('Token Budget', () => {
|
|
5
|
+
test('should have default budget values', () => {
|
|
6
|
+
expect(constants_js_1.DEFAULT_TOKEN_BUDGET.sessionInject).toBe(2000);
|
|
7
|
+
expect(constants_js_1.DEFAULT_TOKEN_BUDGET.searchResults).toBe(1500);
|
|
8
|
+
expect(constants_js_1.DEFAULT_TOKEN_BUDGET.perResult).toBe(500);
|
|
9
|
+
});
|
|
10
|
+
test('should truncate text to approximate token limit', () => {
|
|
11
|
+
// ~4 chars per token heuristic
|
|
12
|
+
const longText = 'a'.repeat(3000);
|
|
13
|
+
const maxChars = 500 * 4; // perResult=500 tokens ≈ 2000 chars
|
|
14
|
+
const truncated = longText.slice(0, maxChars);
|
|
15
|
+
expect(truncated.length).toBeLessThanOrEqual(maxChars);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe('Search Hook — FTS5 Fallback OR Optimization', () => {
|
|
19
|
+
test('should build OR-joined FTS5 MATCH query from keywords', () => {
|
|
20
|
+
const keywords = ['react', 'hooks', 'useEffect'];
|
|
21
|
+
const sanitized = keywords.map(kw => kw.replace(/["*(){}[\]^~:]/g, ''));
|
|
22
|
+
const ftsQuery = sanitized.filter(Boolean).map(kw => `"${kw}"`).join(' OR ');
|
|
23
|
+
expect(ftsQuery).toBe('"react" OR "hooks" OR "useEffect"');
|
|
24
|
+
});
|
|
25
|
+
test('should handle keywords with special characters', () => {
|
|
26
|
+
const keywords = ['react*', '"hooks"', 'use:Effect'];
|
|
27
|
+
const sanitized = keywords.map(kw => kw.replace(/["*(){}[\]^~:]/g, ''));
|
|
28
|
+
const ftsQuery = sanitized.filter(Boolean).map(kw => `"${kw}"`).join(' OR ');
|
|
29
|
+
expect(ftsQuery).toBe('"react" OR "hooks" OR "useEffect"');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=token-budget.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-budget.test.js","sourceRoot":"","sources":["../../tests/token-budget.test.ts"],"names":[],"mappings":";;AAAA,8DAAmE;AAEnE,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,mCAAoB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,mCAAoB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,mCAAoB,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC3D,+BAA+B;QAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,oCAAoC;QAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,IAAI,CAAC,uDAAuD,EAAE,GAAG,EAAE;QACjE,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;QAC1D,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-lint.test.d.ts","sourceRoot":"","sources":["../../tests/wiki-lint.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
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 mindlore_health_check_js_1 = require("../scripts/mindlore-health-check.js");
|
|
10
|
+
describe('wiki lint (contradiction detection)', () => {
|
|
11
|
+
let tmpDir;
|
|
12
|
+
let sourcesDir;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'mindlore-wikilint-'));
|
|
15
|
+
sourcesDir = path_1.default.join(tmpDir, 'sources');
|
|
16
|
+
fs_1.default.mkdirSync(sourcesDir, { recursive: true });
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
it('detects conflicting numeric claims with same tag', () => {
|
|
22
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'a.md'), '---\nslug: a\ntype: source\ntags: [fts5]\n---\nFTS5 has 10 columns.', 'utf8');
|
|
23
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'b.md'), '---\nslug: b\ntype: source\ntags: [fts5]\n---\nFTS5 uses 9 columns.', 'utf8');
|
|
24
|
+
const warnings = (0, mindlore_health_check_js_1.detectWikiContradictions)(tmpDir);
|
|
25
|
+
expect(warnings.length).toBeGreaterThan(0);
|
|
26
|
+
expect(warnings[0]).toMatch(/conflicting values/);
|
|
27
|
+
expect(warnings[0]).toMatch(/10.*9|9.*10/);
|
|
28
|
+
});
|
|
29
|
+
it('no contradiction when values match', () => {
|
|
30
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'a.md'), '---\nslug: a\ntype: source\ntags: [fts5]\n---\nFTS5 has 11 columns.', 'utf8');
|
|
31
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'b.md'), '---\nslug: b\ntype: source\ntags: [fts5]\n---\nFTS5 uses 11 columns.', 'utf8');
|
|
32
|
+
const warnings = (0, mindlore_health_check_js_1.detectWikiContradictions)(tmpDir);
|
|
33
|
+
expect(warnings.length).toBe(0);
|
|
34
|
+
});
|
|
35
|
+
it('ignores files with no tags', () => {
|
|
36
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'a.md'), '---\nslug: a\ntype: source\n---\nFTS5 has 10 columns.', 'utf8');
|
|
37
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'b.md'), '---\nslug: b\ntype: source\n---\nFTS5 uses 9 columns.', 'utf8');
|
|
38
|
+
const warnings = (0, mindlore_health_check_js_1.detectWikiContradictions)(tmpDir);
|
|
39
|
+
expect(warnings.length).toBe(0);
|
|
40
|
+
});
|
|
41
|
+
it('no false positive when only one file has a tag', () => {
|
|
42
|
+
fs_1.default.writeFileSync(path_1.default.join(sourcesDir, 'a.md'), '---\nslug: a\ntype: source\ntags: [fts5]\n---\nFTS5 has 10 columns.', 'utf8');
|
|
43
|
+
const warnings = (0, mindlore_health_check_js_1.detectWikiContradictions)(tmpDir);
|
|
44
|
+
expect(warnings.length).toBe(0);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=wiki-lint.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-lint.test.js","sourceRoot":"","sources":["../../tests/wiki-lint.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -310,7 +310,7 @@ CREATE TABLE IF NOT EXISTS episodes (
|
|
|
310
310
|
/**
|
|
311
311
|
* Valid episode kinds. CO-EVOLUTION: mirrors EPISODE_KINDS in scripts/lib/episodes.ts
|
|
312
312
|
*/
|
|
313
|
-
// ~
|
|
313
|
+
// ~625 tokens context budget for multi-session inject (~4 chars/token)
|
|
314
314
|
const MULTI_SESSION_TOKEN_CAP_CHARS = 2500;
|
|
315
315
|
|
|
316
316
|
const EPISODE_KINDS_CJS = ['session', 'decision', 'event', 'preference', 'learning', 'friction', 'discovery', 'nomination'];
|
|
@@ -554,7 +554,7 @@ const STOP_WORDS = new Set([
|
|
|
554
554
|
'evet', 'hayir', 'tamam', 'ok', 'oldu', 'olur', 'dur',
|
|
555
555
|
'simdi', 'sonra', 'once', 'hemen', 'biraz',
|
|
556
556
|
'lan', 'ya', 'ki', 'abi', 'hadi', 'hey', 'selam',
|
|
557
|
-
'olarak', 'olan', 'gibi', 'kadar', 'daha', 'cok',
|
|
557
|
+
'olarak', 'olan', 'gibi', 'kadar', 'daha', 'cok',
|
|
558
558
|
'bunu', 'buna', 'icinde', 'uzerinde', 'arasinda',
|
|
559
559
|
'sonucu', 'tarafindan', 'zaten', 'gayet',
|
|
560
560
|
'acaba', 'nedir', 'midir', 'mudur',
|
|
@@ -590,6 +590,37 @@ function sanitizeKeyword(kw) {
|
|
|
590
590
|
return clean.length >= 2 ? `"${clean}"` : null;
|
|
591
591
|
}
|
|
592
592
|
|
|
593
|
+
// Derive from compiled constants — single source of truth
|
|
594
|
+
const SHARED_EXPORT_DIRS = (() => {
|
|
595
|
+
try {
|
|
596
|
+
const { DIRECTORIES } = require('../../dist/scripts/lib/constants.js');
|
|
597
|
+
return [...DIRECTORIES, 'memory'];
|
|
598
|
+
} catch {
|
|
599
|
+
return ['raw', 'sources', 'domains', 'analyses', 'insights', 'connections', 'learnings', 'diary', 'decisions', 'memory'];
|
|
600
|
+
}
|
|
601
|
+
})();
|
|
602
|
+
|
|
603
|
+
function resolveWin32Bin(name) {
|
|
604
|
+
if (process.platform === 'win32') {
|
|
605
|
+
try {
|
|
606
|
+
return require('child_process')
|
|
607
|
+
.execSync(`where ${name}`, { encoding: 'utf8', timeout: 3000 })
|
|
608
|
+
.trim().split('\n')[0].trim();
|
|
609
|
+
} catch (_e) { /* fall through */ }
|
|
610
|
+
}
|
|
611
|
+
return name;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Import from compiled TS — single source of truth
|
|
615
|
+
const extractSkeleton = (() => {
|
|
616
|
+
try {
|
|
617
|
+
return require('../../dist/scripts/lib/skeleton.js').extractSkeleton;
|
|
618
|
+
} catch {
|
|
619
|
+
// Fallback: identity function if dist not built
|
|
620
|
+
return (content) => content;
|
|
621
|
+
}
|
|
622
|
+
})();
|
|
623
|
+
|
|
593
624
|
module.exports = {
|
|
594
625
|
MINDLORE_DIR,
|
|
595
626
|
GLOBAL_MINDLORE_DIR,
|
|
@@ -636,6 +667,14 @@ module.exports = {
|
|
|
636
667
|
// Hybrid search helpers (v0.5.0)
|
|
637
668
|
loadSqliteVecCjs,
|
|
638
669
|
hasVecTableCjs,
|
|
670
|
+
// Hook logging (v0.5.1)
|
|
671
|
+
hookLog,
|
|
672
|
+
getRecentHookErrors,
|
|
673
|
+
// Shared helpers (v0.5.1)
|
|
674
|
+
SHARED_EXPORT_DIRS,
|
|
675
|
+
resolveWin32Bin,
|
|
676
|
+
// Skeleton compression (v0.5.2)
|
|
677
|
+
extractSkeleton,
|
|
639
678
|
};
|
|
640
679
|
|
|
641
680
|
/**
|
|
@@ -666,3 +705,71 @@ function hasVecTableCjs(db) {
|
|
|
666
705
|
return false;
|
|
667
706
|
}
|
|
668
707
|
}
|
|
708
|
+
|
|
709
|
+
// --- Hook Logging (v0.5.1) ---
|
|
710
|
+
|
|
711
|
+
function hookLogPath() { return path.join(globalDir(), 'diary', '_hook-log.jsonl'); }
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Append a structured log entry for any mindlore hook.
|
|
715
|
+
* JSONL format — one JSON object per line.
|
|
716
|
+
* Levels: 'info' | 'warn' | 'error'
|
|
717
|
+
* @param {string} hook - Hook name (e.g. 'session-end', 'search', 'read-guard')
|
|
718
|
+
* @param {'info'|'warn'|'error'} level
|
|
719
|
+
* @param {string} message
|
|
720
|
+
*/
|
|
721
|
+
const HOOK_LOG_MAX_BYTES = 512 * 1024; // 500KB
|
|
722
|
+
const HOOK_LOG_KEEP_LINES = 500;
|
|
723
|
+
|
|
724
|
+
function hookLog(hook, level, message) {
|
|
725
|
+
try {
|
|
726
|
+
const logFile = hookLogPath();
|
|
727
|
+
const entry = JSON.stringify({
|
|
728
|
+
ts: new Date().toISOString(),
|
|
729
|
+
hook,
|
|
730
|
+
level,
|
|
731
|
+
msg: message,
|
|
732
|
+
pid: process.pid,
|
|
733
|
+
});
|
|
734
|
+
// Rotate if file exceeds threshold (at most once per hook — each runs as separate process)
|
|
735
|
+
try {
|
|
736
|
+
const stat = fs.statSync(logFile);
|
|
737
|
+
if (stat.size > HOOK_LOG_MAX_BYTES) {
|
|
738
|
+
const lines = fs.readFileSync(logFile, 'utf8').trim().split('\n');
|
|
739
|
+
fs.writeFileSync(logFile, lines.slice(-HOOK_LOG_KEEP_LINES).join('\n') + '\n');
|
|
740
|
+
}
|
|
741
|
+
} catch (_rotateErr) { /* file may not exist yet */ }
|
|
742
|
+
fs.appendFileSync(logFile, entry + '\n');
|
|
743
|
+
} catch (_err) {
|
|
744
|
+
// Best effort — never crash a hook for logging
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Read recent hook errors/warnings since a given ISO date.
|
|
750
|
+
* Returns array of { ts, hook, level, msg } for level 'error' or 'warn'.
|
|
751
|
+
* Used by SessionStart to inject warnings into CC context.
|
|
752
|
+
* @param {string} [since] - ISO date string, defaults to 24h ago
|
|
753
|
+
* @param {number} [limit=10]
|
|
754
|
+
* @returns {Array<{ts: string, hook: string, level: string, msg: string}>}
|
|
755
|
+
*/
|
|
756
|
+
function getRecentHookErrors(since, limit) {
|
|
757
|
+
const maxEntries = limit ?? 10;
|
|
758
|
+
const cutoff = since ?? new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
759
|
+
const results = [];
|
|
760
|
+
try {
|
|
761
|
+
if (!fs.existsSync(hookLogPath())) return results;
|
|
762
|
+
const lines = fs.readFileSync(hookLogPath(), 'utf8').trim().split('\n');
|
|
763
|
+
for (let i = lines.length - 1; i >= 0 && results.length < maxEntries; i--) {
|
|
764
|
+
if (!lines[i]) continue;
|
|
765
|
+
try {
|
|
766
|
+
const entry = JSON.parse(lines[i]);
|
|
767
|
+
if (entry.ts < cutoff) break; // JSONL is chronological, stop early
|
|
768
|
+
if (entry.level === 'error' || entry.level === 'warn') {
|
|
769
|
+
results.push(entry);
|
|
770
|
+
}
|
|
771
|
+
} catch (_parseErr) { /* skip malformed lines */ }
|
|
772
|
+
}
|
|
773
|
+
} catch (_err) { /* silent */ }
|
|
774
|
+
return results.reverse(); // chronological order
|
|
775
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
-
const { findMindloreDir, globalDir } = require('./lib/mindlore-common.cjs');
|
|
18
|
+
const { findMindloreDir, globalDir, hookLog } = require('./lib/mindlore-common.cjs');
|
|
19
19
|
|
|
20
20
|
function main() {
|
|
21
21
|
const cwd = process.cwd();
|
|
@@ -54,4 +54,4 @@ function main() {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
main();
|
|
57
|
+
try { main(); } catch (err) { hookLog('cwd-changed', 'error', err?.message ?? String(err)); }
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Does NOT block (exit 0) — advisory only.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
const { findMindloreDir, readHookStdin } = require('./lib/mindlore-common.cjs');
|
|
12
|
+
const { findMindloreDir, readHookStdin, hookLog } = require('./lib/mindlore-common.cjs');
|
|
13
13
|
|
|
14
14
|
const SIGNALS_TR = [
|
|
15
15
|
'karar verdik', 'karar verildi', 'kararlastirdik', 'kararlaştırdık',
|
|
@@ -48,4 +48,4 @@ function main() {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
main();
|
|
51
|
+
try { main(); } catch (err) { hookLog('decision-detector', 'error', err?.message ?? String(err)); }
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const os = require('os');
|
|
21
|
-
const { findMindloreDir, getProjectName } = require('./lib/mindlore-common.cjs');
|
|
21
|
+
const { findMindloreDir, getProjectName, hookLog } = require('./lib/mindlore-common.cjs');
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* File-persisted pattern cache — survives across process invocations.
|
|
@@ -219,4 +219,4 @@ function main() {
|
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
main();
|
|
222
|
+
try { main(); } catch (err) { hookLog('dont-repeat', 'error', err?.message ?? String(err)); }
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const { MINDLORE_DIR, DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { MINDLORE_DIR, DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, hookLog } = require('./lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
function main() {
|
|
19
19
|
const filePath = readHookStdin(['path', 'file_path']);
|
|
@@ -75,4 +75,4 @@ function main() {
|
|
|
75
75
|
// process.stdout.write kaldırıldı (kimse görmüyor)
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
main();
|
|
78
|
+
try { main(); } catch (err) { hookLog('fts5-sync', 'error', err?.message ?? String(err)); }
|
package/hooks/mindlore-index.cjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { MINDLORE_DIR, DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName } = require('./lib/mindlore-common.cjs');
|
|
13
|
+
const { MINDLORE_DIR, DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, globalDir, hookLog } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
|
|
15
15
|
function main() {
|
|
16
16
|
const filePath = readHookStdin(['path', 'file_path']);
|
|
@@ -19,10 +19,19 @@ function main() {
|
|
|
19
19
|
// Only process .md files inside .mindlore/ (resolved path check prevents traversal)
|
|
20
20
|
if (!filePath.endsWith('.md')) return;
|
|
21
21
|
const resolvedFile = path.resolve(filePath);
|
|
22
|
-
if (!resolvedFile.includes(path.sep + MINDLORE_DIR + path.sep) && !resolvedFile.includes(path.sep + MINDLORE_DIR))
|
|
22
|
+
if (!resolvedFile.includes(path.sep + MINDLORE_DIR + path.sep) && !resolvedFile.includes(path.sep + MINDLORE_DIR)) {
|
|
23
|
+
// CC memory path (~/.claude/projects/*/memory/*.md) — index to global mindlore DB
|
|
24
|
+
const isCcMemory = resolvedFile.includes(path.sep + '.claude' + path.sep + 'projects' + path.sep)
|
|
25
|
+
&& resolvedFile.includes(path.sep + 'memory' + path.sep)
|
|
26
|
+
&& resolvedFile.endsWith('.md');
|
|
27
|
+
if (!isCcMemory) return;
|
|
28
|
+
|
|
29
|
+
// CC memory path — index to global mindlore DB
|
|
30
|
+
indexCcMemory(resolvedFile);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
23
33
|
|
|
24
34
|
const fileName = path.basename(filePath);
|
|
25
|
-
if (SKIP_FILES.has(fileName)) return;
|
|
26
35
|
|
|
27
36
|
// Find the .mindlore dir from the file path
|
|
28
37
|
const mindloreIdx = filePath.indexOf(MINDLORE_DIR);
|
|
@@ -31,6 +40,14 @@ function main() {
|
|
|
31
40
|
|
|
32
41
|
if (!fs.existsSync(dbPath)) return;
|
|
33
42
|
|
|
43
|
+
// Catch-up scan: when INDEX.md or log.md triggers, index recently-modified files
|
|
44
|
+
if (['INDEX.md', 'log.md'].includes(fileName)) {
|
|
45
|
+
catchUpScan(baseDir, dbPath);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (SKIP_FILES.has(fileName)) return;
|
|
50
|
+
|
|
34
51
|
if (!fs.existsSync(filePath)) {
|
|
35
52
|
// File was deleted — remove from index
|
|
36
53
|
const db = openDatabase(dbPath);
|
|
@@ -80,4 +97,125 @@ function main() {
|
|
|
80
97
|
}
|
|
81
98
|
}
|
|
82
99
|
|
|
100
|
+
function indexCcMemory(filePath) {
|
|
101
|
+
const CC_MEMORY_CATEGORY = 'cc-memory';
|
|
102
|
+
// CC memory constants live in TS (scripts/lib/constants.ts) — CJS hooks can't require TS directly
|
|
103
|
+
const globalBase = globalDir();
|
|
104
|
+
const dbPath = path.join(globalBase, DB_NAME);
|
|
105
|
+
|
|
106
|
+
const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
107
|
+
if (!content.trim()) return;
|
|
108
|
+
|
|
109
|
+
// Privacy filter — redact secrets before DB write
|
|
110
|
+
let cleaned = content;
|
|
111
|
+
try {
|
|
112
|
+
const { redactSecrets } = require('../dist/scripts/lib/privacy-filter.js');
|
|
113
|
+
cleaned = redactSecrets(content);
|
|
114
|
+
} catch (_err) {
|
|
115
|
+
// privacy-filter not built — use raw content
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// SHA256 dedup
|
|
119
|
+
const hash = sha256(cleaned);
|
|
120
|
+
const db = openDatabase(dbPath);
|
|
121
|
+
if (!db) return;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const existing = db.prepare('SELECT content_hash FROM file_hashes WHERE path = ?').get(filePath);
|
|
125
|
+
if (existing && existing.content_hash === hash) {
|
|
126
|
+
return; // unchanged — finally handles db.close()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const { meta, body } = parseFrontmatter(cleaned);
|
|
130
|
+
const memType = String(meta.type || 'unknown');
|
|
131
|
+
|
|
132
|
+
// Extract project scope from path: ~/.claude/projects/C--Users-X-proj/memory/
|
|
133
|
+
const projMatch = filePath.match(/projects[/\\]([^/\\]+)[/\\]memory/);
|
|
134
|
+
const projectScope = projMatch ? projMatch[1] : null;
|
|
135
|
+
|
|
136
|
+
const ftsData = extractFtsMetadata(meta, body, filePath, globalBase);
|
|
137
|
+
|
|
138
|
+
// Update FTS5 + hash atomically
|
|
139
|
+
const updateIndex = db.transaction(() => {
|
|
140
|
+
db.prepare('DELETE FROM mindlore_fts WHERE path = ?').run(filePath);
|
|
141
|
+
insertFtsRow(db, {
|
|
142
|
+
path: filePath,
|
|
143
|
+
...ftsData,
|
|
144
|
+
category: CC_MEMORY_CATEGORY,
|
|
145
|
+
type: memType,
|
|
146
|
+
project: projectScope,
|
|
147
|
+
});
|
|
148
|
+
db.prepare(
|
|
149
|
+
`INSERT INTO file_hashes (path, content_hash, last_indexed, source_type, project_scope)
|
|
150
|
+
VALUES (?, ?, ?, ?, ?)
|
|
151
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
152
|
+
content_hash = excluded.content_hash,
|
|
153
|
+
last_indexed = excluded.last_indexed,
|
|
154
|
+
source_type = excluded.source_type,
|
|
155
|
+
project_scope = excluded.project_scope`
|
|
156
|
+
).run(filePath, hash, new Date().toISOString(), CC_MEMORY_CATEGORY, projectScope);
|
|
157
|
+
});
|
|
158
|
+
updateIndex();
|
|
159
|
+
|
|
160
|
+
// Copy to ~/.mindlore/memory/{project}/ for git-sync + obsidian
|
|
161
|
+
const memoryDir = path.join(globalBase, 'memory', projectScope || '_global');
|
|
162
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
163
|
+
const destPath = path.join(memoryDir, path.basename(filePath));
|
|
164
|
+
fs.writeFileSync(destPath, cleaned, 'utf8');
|
|
165
|
+
} finally {
|
|
166
|
+
db.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function catchUpScan(baseDir, dbPath) {
|
|
171
|
+
const CATCH_UP_DIRS = ['raw', 'sources', 'analyses', 'diary'];
|
|
172
|
+
const fiveMinAgo = Date.now() - 5 * 60 * 1000;
|
|
173
|
+
|
|
174
|
+
const db = openDatabase(dbPath);
|
|
175
|
+
if (!db) return;
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
let indexed = 0;
|
|
179
|
+
for (const dir of CATCH_UP_DIRS) {
|
|
180
|
+
const dirPath = path.join(baseDir, dir);
|
|
181
|
+
if (!fs.existsSync(dirPath)) continue;
|
|
182
|
+
|
|
183
|
+
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.md'));
|
|
184
|
+
for (const file of files) {
|
|
185
|
+
const filePath = path.join(dirPath, file);
|
|
186
|
+
const stat = fs.statSync(filePath);
|
|
187
|
+
if (stat.mtimeMs < fiveMinAgo) continue;
|
|
188
|
+
|
|
189
|
+
const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
190
|
+
const hash = sha256(content);
|
|
191
|
+
|
|
192
|
+
const existing = db.prepare('SELECT content_hash FROM file_hashes WHERE path = ?').get(filePath);
|
|
193
|
+
if (existing && existing.content_hash === hash) continue;
|
|
194
|
+
|
|
195
|
+
const { meta, body } = parseFrontmatter(content);
|
|
196
|
+
const ftsData = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
197
|
+
|
|
198
|
+
const update = db.transaction(() => {
|
|
199
|
+
db.prepare('DELETE FROM mindlore_fts WHERE path = ?').run(filePath);
|
|
200
|
+
insertFtsRow(db, { path: filePath, ...ftsData, project: getProjectName() });
|
|
201
|
+
db.prepare(
|
|
202
|
+
`INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
203
|
+
VALUES (?, ?, ?)
|
|
204
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
205
|
+
content_hash = excluded.content_hash,
|
|
206
|
+
last_indexed = excluded.last_indexed`
|
|
207
|
+
).run(filePath, hash, new Date().toISOString());
|
|
208
|
+
});
|
|
209
|
+
update();
|
|
210
|
+
indexed++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (indexed > 0) {
|
|
214
|
+
hookLog(`catch-up: ${indexed} file(s) indexed`);
|
|
215
|
+
}
|
|
216
|
+
} finally {
|
|
217
|
+
db.close();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
83
221
|
main();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
|
-
const { findMindloreDir, readConfig, DEFAULT_MODELS } = require('./lib/mindlore-common.cjs');
|
|
9
|
+
const { findMindloreDir, readConfig, DEFAULT_MODELS, hookLog } = require('./lib/mindlore-common.cjs');
|
|
10
10
|
|
|
11
11
|
const SKILL_KEYS = Object.keys(DEFAULT_MODELS).filter((k) => k !== 'default');
|
|
12
12
|
const MARKER_REGEX = new RegExp(`\\[mindlore:(${SKILL_KEYS.join('|')})\\]`);
|
|
@@ -51,4 +51,4 @@ function main() {
|
|
|
51
51
|
process.stdout.write(JSON.stringify(output));
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
main();
|
|
54
|
+
try { main(); } catch (err) { hookLog('model-router', 'error', err?.message ?? String(err)); }
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
|
-
const { findMindloreDir, getLatestDelta } = require('./lib/mindlore-common.cjs');
|
|
17
|
+
const { findMindloreDir, getLatestDelta, hookLog } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
function main() {
|
|
20
20
|
const baseDir = findMindloreDir();
|
|
@@ -43,4 +43,4 @@ function main() {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
main();
|
|
46
|
+
try { main(); } catch (err) { hookLog('post-compact', 'error', err?.message ?? String(err)); }
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const { findMindloreDir, getProjectName } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { findMindloreDir, getProjectName, hookLog } = require('./lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
const CODE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.rs', '.go', '.java', '.c', '.cpp', '.h', '.css', '.scss', '.sql', '.sh', '.yaml', '.yml', '.json', '.toml', '.xml', '.cjs', '.mjs']);
|
|
19
19
|
const PROSE_EXTS = new Set(['.md', '.txt', '.rst', '.adoc']);
|
|
@@ -103,4 +103,4 @@ function main() {
|
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
main();
|
|
106
|
+
try { main(); } catch (err) { hookLog('post-read', 'error', err?.message ?? String(err)); }
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
|
-
const { findMindloreDir } = require('./lib/mindlore-common.cjs');
|
|
14
|
+
const { findMindloreDir, hookLog } = require('./lib/mindlore-common.cjs');
|
|
15
15
|
|
|
16
16
|
function main() {
|
|
17
17
|
const baseDir = findMindloreDir();
|
|
@@ -45,4 +45,4 @@ function main() {
|
|
|
45
45
|
process.stdout.write('[Mindlore: pre-compact FTS5 flush complete]\n');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
main();
|
|
48
|
+
try { main(); } catch (err) { hookLog('pre-compact', 'error', err?.message ?? String(err)); }
|