mindlore 0.5.1 → 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.
Files changed (90) hide show
  1. package/README.md +15 -2
  2. package/dist/scripts/fetch-raw.d.ts +2 -0
  3. package/dist/scripts/fetch-raw.d.ts.map +1 -0
  4. package/dist/scripts/fetch-raw.js +124 -0
  5. package/dist/scripts/fetch-raw.js.map +1 -0
  6. package/dist/scripts/lib/constants.d.ts +2 -0
  7. package/dist/scripts/lib/constants.d.ts.map +1 -1
  8. package/dist/scripts/lib/constants.js +13 -4
  9. package/dist/scripts/lib/constants.js.map +1 -1
  10. package/dist/scripts/lib/db-helpers.d.ts +12 -2
  11. package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
  12. package/dist/scripts/lib/db-helpers.js +36 -0
  13. package/dist/scripts/lib/db-helpers.js.map +1 -1
  14. package/dist/scripts/lib/hybrid-search.d.ts +0 -2
  15. package/dist/scripts/lib/hybrid-search.d.ts.map +1 -1
  16. package/dist/scripts/lib/hybrid-search.js +7 -1
  17. package/dist/scripts/lib/hybrid-search.js.map +1 -1
  18. package/dist/scripts/lib/migrations-v052.d.ts +3 -0
  19. package/dist/scripts/lib/migrations-v052.d.ts.map +1 -0
  20. package/dist/scripts/lib/migrations-v052.js +23 -0
  21. package/dist/scripts/lib/migrations-v052.js.map +1 -0
  22. package/dist/scripts/lib/skeleton.d.ts +2 -0
  23. package/dist/scripts/lib/skeleton.d.ts.map +1 -0
  24. package/dist/scripts/lib/skeleton.js +99 -0
  25. package/dist/scripts/lib/skeleton.js.map +1 -0
  26. package/dist/scripts/lib/skill-memory.d.ts +13 -0
  27. package/dist/scripts/lib/skill-memory.d.ts.map +1 -0
  28. package/dist/scripts/lib/skill-memory.js +94 -0
  29. package/dist/scripts/lib/skill-memory.js.map +1 -0
  30. package/dist/scripts/mindlore-fts5-index.js +2 -1
  31. package/dist/scripts/mindlore-fts5-index.js.map +1 -1
  32. package/dist/scripts/mindlore-health-check.d.ts +1 -1
  33. package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
  34. package/dist/scripts/mindlore-health-check.js +110 -142
  35. package/dist/scripts/mindlore-health-check.js.map +1 -1
  36. package/dist/tests/catch-up.test.d.ts +2 -0
  37. package/dist/tests/catch-up.test.d.ts.map +1 -0
  38. package/dist/tests/catch-up.test.js +88 -0
  39. package/dist/tests/catch-up.test.js.map +1 -0
  40. package/dist/tests/episode-file.test.js +9 -6
  41. package/dist/tests/episode-file.test.js.map +1 -1
  42. package/dist/tests/fetch-raw.test.d.ts +2 -0
  43. package/dist/tests/fetch-raw.test.d.ts.map +1 -0
  44. package/dist/tests/fetch-raw.test.js +43 -0
  45. package/dist/tests/fetch-raw.test.js.map +1 -0
  46. package/dist/tests/resolve-hook-common.test.d.ts +2 -0
  47. package/dist/tests/resolve-hook-common.test.d.ts.map +1 -0
  48. package/dist/tests/resolve-hook-common.test.js +30 -0
  49. package/dist/tests/resolve-hook-common.test.js.map +1 -0
  50. package/dist/tests/search-offload.test.d.ts +2 -0
  51. package/dist/tests/search-offload.test.d.ts.map +1 -0
  52. package/dist/tests/search-offload.test.js +34 -0
  53. package/dist/tests/search-offload.test.js.map +1 -0
  54. package/dist/tests/skeleton.test.d.ts +2 -0
  55. package/dist/tests/skeleton.test.d.ts.map +1 -0
  56. package/dist/tests/skeleton.test.js +116 -0
  57. package/dist/tests/skeleton.test.js.map +1 -0
  58. package/dist/tests/skill-memory-api.test.d.ts +2 -0
  59. package/dist/tests/skill-memory-api.test.d.ts.map +1 -0
  60. package/dist/tests/skill-memory-api.test.js +62 -0
  61. package/dist/tests/skill-memory-api.test.js.map +1 -0
  62. package/dist/tests/skill-memory.test.d.ts +2 -0
  63. package/dist/tests/skill-memory.test.d.ts.map +1 -0
  64. package/dist/tests/skill-memory.test.js +67 -0
  65. package/dist/tests/skill-memory.test.js.map +1 -0
  66. package/dist/tests/wiki-lint.test.d.ts +2 -0
  67. package/dist/tests/wiki-lint.test.d.ts.map +1 -0
  68. package/dist/tests/wiki-lint.test.js +47 -0
  69. package/dist/tests/wiki-lint.test.js.map +1 -0
  70. package/hooks/lib/mindlore-common.cjs +24 -5
  71. package/hooks/mindlore-cwd-changed.cjs +2 -2
  72. package/hooks/mindlore-decision-detector.cjs +2 -2
  73. package/hooks/mindlore-dont-repeat.cjs +2 -2
  74. package/hooks/mindlore-fts5-sync.cjs +2 -2
  75. package/hooks/mindlore-index.cjs +60 -2
  76. package/hooks/mindlore-model-router.cjs +2 -2
  77. package/hooks/mindlore-post-compact.cjs +2 -2
  78. package/hooks/mindlore-post-read.cjs +2 -2
  79. package/hooks/mindlore-pre-compact.cjs +2 -2
  80. package/hooks/mindlore-read-guard.cjs +15 -3
  81. package/hooks/mindlore-research-guard.cjs +2 -2
  82. package/hooks/mindlore-search.cjs +20 -2
  83. package/hooks/mindlore-session-end.cjs +1 -1
  84. package/package.json +3 -2
  85. package/plugin.json +29 -2
  86. package/skills/mindlore-diary/SKILL.md +76 -0
  87. package/skills/mindlore-ingest/SKILL.md +41 -49
  88. package/skills/mindlore-log/SKILL.md +3 -143
  89. package/skills/mindlore-reflect/SKILL.md +104 -0
  90. package/templates/config.json +1 -1
@@ -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":";;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,4CAAoB;AACpB,kFAA+E;AAE/E,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,IAAI,MAAc,CAAC;IACnB,IAAI,UAAkB,CAAC;IAEvB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,YAAE,CAAC,WAAW,CAAC,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACtE,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC1C,YAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,YAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,qEAAqE,EACrE,MAAM,CACP,CAAC;QACF,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,qEAAqE,EACrE,MAAM,CACP,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAA,mDAAwB,EAAC,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,qEAAqE,EACrE,MAAM,CACP,CAAC;QACF,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,sEAAsE,EACtE,MAAM,CACP,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAA,mDAAwB,EAAC,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,uDAAuD,EACvD,MAAM,CACP,CAAC;QACF,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,uDAAuD,EACvD,MAAM,CACP,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAA,mDAAwB,EAAC,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,YAAE,CAAC,aAAa,CACd,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,EAC7B,qEAAqE,EACrE,MAAM,CACP,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAA,mDAAwB,EAAC,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -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
- // ~500 tokens context budget for multi-session inject
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', 'hem',
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,8 +590,15 @@ function sanitizeKeyword(kw) {
590
590
  return clean.length >= 2 ? `"${clean}"` : null;
591
591
  }
592
592
 
593
- // Matches DIRECTORIES in scripts/lib/constants.ts + 'memory' (v0.5.1 CC memory sync)
594
- const SHARED_EXPORT_DIRS = ['raw', 'sources', 'domains', 'analyses', 'insights', 'connections', 'learnings', 'diary', 'decisions', 'memory'];
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
+ })();
595
602
 
596
603
  function resolveWin32Bin(name) {
597
604
  if (process.platform === 'win32') {
@@ -604,6 +611,16 @@ function resolveWin32Bin(name) {
604
611
  return name;
605
612
  }
606
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
+
607
624
  module.exports = {
608
625
  MINDLORE_DIR,
609
626
  GLOBAL_MINDLORE_DIR,
@@ -656,6 +673,8 @@ module.exports = {
656
673
  // Shared helpers (v0.5.1)
657
674
  SHARED_EXPORT_DIRS,
658
675
  resolveWin32Bin,
676
+ // Skeleton compression (v0.5.2)
677
+ extractSkeleton,
659
678
  };
660
679
 
661
680
  /**
@@ -712,7 +731,7 @@ function hookLog(hook, level, message) {
712
731
  msg: message,
713
732
  pid: process.pid,
714
733
  });
715
- // Rotate if file exceeds threshold
734
+ // Rotate if file exceeds threshold (at most once per hook — each runs as separate process)
716
735
  try {
717
736
  const stat = fs.statSync(logFile);
718
737
  if (stat.size > HOOK_LOG_MAX_BYTES) {
@@ -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)); }
@@ -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, globalDir } = 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']);
@@ -32,7 +32,6 @@ function main() {
32
32
  }
33
33
 
34
34
  const fileName = path.basename(filePath);
35
- if (SKIP_FILES.has(fileName)) return;
36
35
 
37
36
  // Find the .mindlore dir from the file path
38
37
  const mindloreIdx = filePath.indexOf(MINDLORE_DIR);
@@ -41,6 +40,14 @@ function main() {
41
40
 
42
41
  if (!fs.existsSync(dbPath)) return;
43
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
+
44
51
  if (!fs.existsSync(filePath)) {
45
52
  // File was deleted — remove from index
46
53
  const db = openDatabase(dbPath);
@@ -160,4 +167,55 @@ function indexCcMemory(filePath) {
160
167
  }
161
168
  }
162
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
+
163
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)); }
@@ -14,7 +14,7 @@
14
14
 
15
15
  const fs = require('fs');
16
16
  const path = require('path');
17
- const { findMindloreDir, readHookStdin, getProjectName } = require('./lib/mindlore-common.cjs');
17
+ const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton } = require('./lib/mindlore-common.cjs');
18
18
 
19
19
  function main() {
20
20
  const baseDir = findMindloreDir();
@@ -81,13 +81,25 @@ function main() {
81
81
  // Warn on 2nd read (exit 0 = allow but warn)
82
82
  if (count > 1) {
83
83
  const totalWaste = tokens > 0 ? ` Toplam tekrar: ~${tokens * (count - 1)} token.` : '';
84
+ let skeletonSection = '';
85
+ try {
86
+ const ext = path.extname(filePath).slice(1);
87
+ const fileContent = fs.readFileSync(filePath, 'utf8');
88
+ if (fileContent.length < 500_000) {
89
+ const skeleton = extractSkeleton(fileContent, ext);
90
+ if (skeleton !== fileContent) {
91
+ const truncated = skeleton.length > 2000 ? skeleton.slice(0, 2000) + '\n...[truncated]' : skeleton;
92
+ skeletonSection = '\n\n' + truncated;
93
+ }
94
+ }
95
+ } catch (_e) { /* unreadable/binary — skip */ }
84
96
  process.stdout.write(JSON.stringify({
85
97
  hookSpecificOutput: {
86
98
  hookEventName: 'PreToolUse',
87
- additionalContext: `[Mindlore: ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Bir sonraki okuma engellenecek — Edit gerekiyorsa simdi yap.]`
99
+ additionalContext: `[Mindlore: ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Bir sonraki okuma engellenecek — Edit gerekiyorsa simdi yap.]${skeletonSection}`
88
100
  }
89
101
  }));
90
102
  }
91
103
  }
92
104
 
93
- main();
105
+ try { main(); } catch (err) { hookLog('read-guard', '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 { getAllDbs, requireDatabase, extractKeywords, sanitizeKeyword } = require('./lib/mindlore-common.cjs');
17
+ const { getAllDbs, requireDatabase, extractKeywords, sanitizeKeyword, hookLog } = require('./lib/mindlore-common.cjs');
18
18
 
19
19
  // Keywords that signal a research/web-search intent in agent prompts
20
20
  // Note: entries with dots/stars are regex patterns, rest are literals
@@ -141,4 +141,4 @@ function main() {
141
141
  process.stdout.write(JSON.stringify(output));
142
142
  }
143
143
 
144
- main();
144
+ try { main(); } catch (err) { hookLog('research-guard', 'error', err?.message ?? String(err)); }
@@ -154,7 +154,7 @@ function main() {
154
154
  }
155
155
 
156
156
  // Sort: most keyword hits first, then best rank
157
- allScores.sort((a, b) => b.hits - a.hits || a.totalRank - b.totalRank);
157
+ allScores.sort((a, b) => b.hits - a.hits || a.rank - b.rank);
158
158
 
159
159
  // Deduplicate by full path (project version wins — appears first in sort)
160
160
  const seen = new Set();
@@ -225,7 +225,25 @@ function main() {
225
225
  }
226
226
 
227
227
  if (output.length > 0) {
228
- process.stdout.write(output.join('\n\n') + '\n');
228
+ let outputStr = output.join('\n\n') + '\n';
229
+
230
+ const OFFLOAD_THRESHOLD = 10240; // 10KB
231
+ if (outputStr.length > OFFLOAD_THRESHOLD) {
232
+ const baseDir = path.dirname(dbPaths[0]);
233
+ const tmpDir = path.join(baseDir, 'tmp');
234
+ fs.mkdirSync(tmpDir, { recursive: true });
235
+ const fileName = `search-${Date.now()}.md`;
236
+ const filePath = path.join(tmpDir, fileName);
237
+ fs.writeFileSync(filePath, outputStr, 'utf8');
238
+
239
+ const summary = outputStr.slice(0, 500).replace(/\n/g, ' ').trim();
240
+ outputStr = `[Mindlore Search: ${outputStr.length} chars offloaded to ${filePath}]\n` +
241
+ `Summary: ${summary}...\n` +
242
+ `[Read full results: ${filePath}]`;
243
+ hookLog('search', 'info', 'offloaded to tmp/ (' + outputStr.length + ' chars)');
244
+ }
245
+
246
+ process.stdout.write(outputStr);
229
247
  }
230
248
  }
231
249
 
@@ -291,7 +291,7 @@ function writeEpisodeFile(baseDir, project, commits, changedFiles, reads) {
291
291
  const projDir = path.join(baseDir, 'diary', project || 'unknown');
292
292
  if (!fs.existsSync(projDir)) fs.mkdirSync(projDir, { recursive: true });
293
293
 
294
- const now = new Date();
294
+ const now = process.env.MINDLORE_EPISODE_TS ? new Date(process.env.MINDLORE_EPISODE_TS) : new Date();
295
295
  const ts = formatDate(now);
296
296
  const filePath = path.join(projDir, `episode-${ts}.md`);
297
297
  if (fs.existsSync(filePath)) return; // idempotent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindlore",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "AI-native knowledge system for Claude Code",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -17,7 +17,8 @@
17
17
  "health": "node dist/scripts/mindlore-health-check.js",
18
18
  "index": "node dist/scripts/mindlore-fts5-index.js",
19
19
  "search": "node dist/scripts/mindlore-fts5-search.js",
20
- "quality": "node dist/scripts/quality-populate.js"
20
+ "quality": "node dist/scripts/quality-populate.js",
21
+ "fetch-raw": "node dist/scripts/fetch-raw.js"
21
22
  },
22
23
  "keywords": [
23
24
  "claude-code",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mindlore",
3
3
  "description": "AI-native knowledge system for Claude Code. Persistent, searchable, evolving knowledge base with FTS5.",
4
- "version": "0.5.1",
4
+ "version": "0.5.2",
5
5
  "skills": [
6
6
  {
7
7
  "name": "mindlore-ingest",
@@ -21,7 +21,17 @@
21
21
  {
22
22
  "name": "mindlore-log",
23
23
  "path": "skills/mindlore-log/SKILL.md",
24
- "description": "Session logging, pattern extraction, and wiki updates. Modes: diary (LLM session analysis to enriched episodes: decisions, discoveries, frictions, learnings, preferences, events), reflect (scan episodes for recurring patterns, 3-tier confidence assessment, nomination pipeline for rule proposals), status (recent sessions summary with trends), save (structured delta + log.md append + domain wiki update). Episodes-powered since v0.4.0."
24
+ "description": "Session logging and wiki updates. Modes: log (manual diary entry), status (recent sessions summary with trends), save (structured delta + log.md append + domain wiki update). For diary analysis use /mindlore-diary; for pattern extraction use /mindlore-reflect."
25
+ },
26
+ {
27
+ "name": "mindlore-diary",
28
+ "path": "skills/mindlore-diary/SKILL.md",
29
+ "description": "LLM-powered session analysis: decisions, discoveries, frictions, learnings. Promotes episodes to semantic knowledge with 3-tier confidence. Reads/writes skill_memory for continuity."
30
+ },
31
+ {
32
+ "name": "mindlore-reflect",
33
+ "path": "skills/mindlore-reflect/SKILL.md",
34
+ "description": "Pattern extraction from episodes: recurring decisions, frictions, discoveries. 3-tier confidence (Note/Learning/Nomination), nomination pipeline with approval flow, CLAUDE.md update proposals."
25
35
  },
26
36
  {
27
37
  "name": "mindlore-decide",
@@ -39,6 +49,23 @@
39
49
  "description": "Discover unexpected connections between knowledge sources — undirected exploration mode. Cross-references domains, sources, analyses, and episodes to find non-obvious relationships. Identifies: shared entities across sources, pattern convergence between domains, episodic evidence supporting or contradicting domain claims. Default scope: project + global (--scope project|global|all)."
40
50
  }
41
51
  ],
52
+ "agents": [
53
+ {
54
+ "name": "mindlore-assistant",
55
+ "path": "agents/mindlore-assistant.md",
56
+ "description": "Knowledge base Q&A with hybrid search and citations"
57
+ },
58
+ {
59
+ "name": "mindlore-researcher",
60
+ "path": "agents/mindlore-researcher.md",
61
+ "description": "Independent web research with source comparison"
62
+ },
63
+ {
64
+ "name": "mindlore-librarian",
65
+ "path": "agents/mindlore-librarian.md",
66
+ "description": "Periodic maintenance, stale detection, health trends"
67
+ }
68
+ ],
42
69
  "hooks": [
43
70
  {
44
71
  "event": "SessionStart",
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: mindlore-diary
3
+ description: LLM-powered session analysis — decisions, discoveries, frictions, learnings. Promotes episodes to semantic knowledge.
4
+ ---
5
+
6
+ # /mindlore-diary
7
+
8
+ ## Scope
9
+
10
+ Determine target using `getActiveMindloreDir()` logic:
11
+ - If CWD has `.mindlore/` -> project scope
12
+ - Otherwise -> global `~/.mindlore/`
13
+
14
+ ## Trigger
15
+
16
+ `/mindlore-diary` or `/mindlore-log diary`
17
+
18
+ ## On Start — Read skill_memory
19
+
20
+ ```bash
21
+ node dist/scripts/lib/skill-memory.js get mindlore-diary last_diary_date
22
+ ```
23
+ If last_diary_date is today, warn: "Diary already ran today. Continue anyway?"
24
+
25
+ ## Flow
26
+
27
+ 1. Read active episodes: `WHERE status = 'active' AND source IN ('hook', 'diary')`
28
+ 2. Filter by time: default last 24h, or `--days N` flag
29
+ 3. Present summary: "Found N episodes spanning DATE1 to DATE2"
30
+ 4. LLM analyzes episodes for semantic patterns:
31
+ - **Decisions:** choices made, alternatives considered
32
+ - **Discoveries:** new insights, broken assumptions
33
+ - **Frictions:** recurring blockers, errors, slowdowns
34
+ - **Learnings:** techniques that worked, patterns validated
35
+ - **Preferences:** user workflow preferences detected
36
+ - **Events:** notable milestones, completions
37
+
38
+ 5. For each detected item, create enriched episode:
39
+ ```sql
40
+ INSERT INTO episodes (summary, body, kind, source, status, project, created_at)
41
+ VALUES (?, ?, ?, 'diary', 'active', ?, ?)
42
+ ```
43
+ Where kind = 'decision' | 'discovery' | 'friction' | 'learning' | 'preference' | 'event'
44
+
45
+ 6. Output structured report:
46
+ ```
47
+ -- Diary Raporu ({date}, {N} episode analiz edildi) --
48
+
49
+ Decisions ({count}):
50
+ - {summary}
51
+
52
+ Discoveries ({count}):
53
+ - {summary}
54
+
55
+ Frictions ({count}):
56
+ - {summary}
57
+
58
+ Learnings ({count}):
59
+ - {summary}
60
+
61
+ {M} yeni episode olusturuldu.
62
+ ```
63
+
64
+ ## On End — Write skill_memory
65
+
66
+ ```bash
67
+ node dist/scripts/lib/skill-memory.js set mindlore-diary last_diary_date "$(date -I)"
68
+ node dist/scripts/lib/skill-memory.js set mindlore-diary last_episode_count "{N}"
69
+ ```
70
+
71
+ ## Rules
72
+
73
+ - NEVER create episodes without user seeing the analysis first
74
+ - Each episode must have proper `kind` field — don't default everything to 'event'
75
+ - Group related items — don't create 5 episodes for the same friction
76
+ - Append to `log.md`: `| {date} | diary | {N} episodes created |`