mindlore 0.6.6 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +259 -259
  2. package/SCHEMA.md +292 -292
  3. package/dist/scripts/cc-memory-bulk-sync.d.ts.map +1 -1
  4. package/dist/scripts/cc-memory-bulk-sync.js +47 -42
  5. package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
  6. package/dist/scripts/cc-session-sync.d.ts.map +1 -1
  7. package/dist/scripts/cc-session-sync.js +58 -48
  8. package/dist/scripts/cc-session-sync.js.map +1 -1
  9. package/dist/scripts/init.js +8 -8
  10. package/dist/scripts/init.js.map +1 -1
  11. package/dist/scripts/lib/all-migrations.d.ts.map +1 -1
  12. package/dist/scripts/lib/all-migrations.js +7 -1
  13. package/dist/scripts/lib/all-migrations.js.map +1 -1
  14. package/dist/scripts/lib/consolidation.d.ts +4 -3
  15. package/dist/scripts/lib/consolidation.d.ts.map +1 -1
  16. package/dist/scripts/lib/consolidation.js +10 -10
  17. package/dist/scripts/lib/consolidation.js.map +1 -1
  18. package/dist/scripts/lib/constants.d.ts +1 -7
  19. package/dist/scripts/lib/constants.d.ts.map +1 -1
  20. package/dist/scripts/lib/constants.js +2 -9
  21. package/dist/scripts/lib/constants.js.map +1 -1
  22. package/dist/scripts/lib/db-helpers.d.ts +0 -15
  23. package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
  24. package/dist/scripts/lib/db-helpers.js +1 -51
  25. package/dist/scripts/lib/db-helpers.js.map +1 -1
  26. package/dist/scripts/lib/decay.d.ts.map +1 -1
  27. package/dist/scripts/lib/decay.js +9 -9
  28. package/dist/scripts/lib/decay.js.map +1 -1
  29. package/dist/scripts/lib/episodes.js +23 -23
  30. package/dist/scripts/lib/migrations-v061.js +21 -21
  31. package/dist/scripts/lib/migrations-v062.js +11 -11
  32. package/dist/scripts/lib/migrations-v063.js +14 -14
  33. package/dist/scripts/lib/migrations-v067.d.ts +7 -0
  34. package/dist/scripts/lib/migrations-v067.d.ts.map +1 -0
  35. package/dist/scripts/lib/migrations-v067.js +50 -0
  36. package/dist/scripts/lib/migrations-v067.js.map +1 -0
  37. package/dist/scripts/lib/migrations-v068.d.ts +3 -0
  38. package/dist/scripts/lib/migrations-v068.d.ts.map +1 -0
  39. package/dist/scripts/lib/migrations-v068.js +37 -0
  40. package/dist/scripts/lib/migrations-v068.js.map +1 -0
  41. package/dist/scripts/lib/migrations.d.ts.map +1 -1
  42. package/dist/scripts/lib/migrations.js +0 -15
  43. package/dist/scripts/lib/migrations.js.map +1 -1
  44. package/dist/scripts/lib/schema-version.js +6 -6
  45. package/dist/scripts/lib/search-cache.js +11 -11
  46. package/dist/scripts/lib/session-payload.d.ts +9 -1
  47. package/dist/scripts/lib/session-payload.d.ts.map +1 -1
  48. package/dist/scripts/lib/session-payload.js +11 -10
  49. package/dist/scripts/lib/session-payload.js.map +1 -1
  50. package/dist/scripts/lib/triage.js +3 -3
  51. package/dist/scripts/mindlore-backup.js +9 -9
  52. package/dist/scripts/mindlore-fts5-index.d.ts +1 -2
  53. package/dist/scripts/mindlore-fts5-index.d.ts.map +1 -1
  54. package/dist/scripts/mindlore-fts5-index.js +12 -64
  55. package/dist/scripts/mindlore-fts5-index.js.map +1 -1
  56. package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
  57. package/dist/scripts/mindlore-health-check.js +0 -11
  58. package/dist/scripts/mindlore-health-check.js.map +1 -1
  59. package/dist/tests/cc-memory-bulk-sync.test.js +23 -0
  60. package/dist/tests/cc-memory-bulk-sync.test.js.map +1 -1
  61. package/dist/tests/cc-session-sync.test.js +25 -0
  62. package/dist/tests/cc-session-sync.test.js.map +1 -1
  63. package/dist/tests/compaction-snapshot.test.js +2 -2
  64. package/dist/tests/consolidation.test.js +5 -5
  65. package/dist/tests/consolidation.test.js.map +1 -1
  66. package/dist/tests/decay.test.js +9 -9
  67. package/dist/tests/diary.test.js +4 -4
  68. package/dist/tests/episode-kind-constant.test.d.ts +2 -0
  69. package/dist/tests/episode-kind-constant.test.d.ts.map +1 -0
  70. package/dist/tests/episode-kind-constant.test.js +28 -0
  71. package/dist/tests/episode-kind-constant.test.js.map +1 -0
  72. package/dist/tests/episodes-inject.test.js +14 -14
  73. package/dist/tests/episodes-inject.test.js.map +1 -1
  74. package/dist/tests/fts5.test.js +66 -125
  75. package/dist/tests/fts5.test.js.map +1 -1
  76. package/dist/tests/globalSetup.d.ts +2 -0
  77. package/dist/tests/globalSetup.d.ts.map +1 -0
  78. package/dist/tests/globalSetup.js +36 -0
  79. package/dist/tests/globalSetup.js.map +1 -0
  80. package/dist/tests/helpers/db.d.ts +13 -5
  81. package/dist/tests/helpers/db.d.ts.map +1 -1
  82. package/dist/tests/helpers/db.js +61 -33
  83. package/dist/tests/helpers/db.js.map +1 -1
  84. package/dist/tests/lesson-graduation.test.d.ts +2 -0
  85. package/dist/tests/lesson-graduation.test.d.ts.map +1 -0
  86. package/dist/tests/lesson-graduation.test.js +83 -0
  87. package/dist/tests/lesson-graduation.test.js.map +1 -0
  88. package/dist/tests/migrations-v053.test.js +16 -16
  89. package/dist/tests/migrations-v061.test.js +10 -10
  90. package/dist/tests/migrations-v063.test.js +2 -2
  91. package/dist/tests/migrations-v067.test.d.ts +2 -0
  92. package/dist/tests/migrations-v067.test.d.ts.map +1 -0
  93. package/dist/tests/migrations-v067.test.js +115 -0
  94. package/dist/tests/migrations-v067.test.js.map +1 -0
  95. package/dist/tests/migrations-v068.test.d.ts +2 -0
  96. package/dist/tests/migrations-v068.test.d.ts.map +1 -0
  97. package/dist/tests/migrations-v068.test.js +53 -0
  98. package/dist/tests/migrations-v068.test.js.map +1 -0
  99. package/dist/tests/nomination-counts.test.d.ts +2 -0
  100. package/dist/tests/nomination-counts.test.d.ts.map +1 -0
  101. package/dist/tests/nomination-counts.test.js +51 -0
  102. package/dist/tests/nomination-counts.test.js.map +1 -0
  103. package/dist/tests/recall-telemetry.test.js +8 -8
  104. package/dist/tests/schema-version.test.js +3 -7
  105. package/dist/tests/schema-version.test.js.map +1 -1
  106. package/dist/tests/search-hook.test.js +2 -2
  107. package/dist/tests/sec-regression.test.js +0 -50
  108. package/dist/tests/sec-regression.test.js.map +1 -1
  109. package/dist/tests/session-end-cleanup.test.d.ts +2 -0
  110. package/dist/tests/session-end-cleanup.test.d.ts.map +1 -0
  111. package/dist/tests/session-end-cleanup.test.js +59 -0
  112. package/dist/tests/session-end-cleanup.test.js.map +1 -0
  113. package/dist/tests/session-focus.test.js +69 -10
  114. package/dist/tests/session-focus.test.js.map +1 -1
  115. package/dist/tests/session-payload.test.js +11 -11
  116. package/dist/tests/session-payload.test.js.map +1 -1
  117. package/dist/tests/session-summary.test.js +2 -2
  118. package/dist/tests/session-summary.test.js.map +1 -1
  119. package/hooks/lib/constants.cjs +15 -0
  120. package/hooks/lib/mindlore-common.cjs +974 -1004
  121. package/hooks/mindlore-cwd-changed.cjs +57 -57
  122. package/hooks/mindlore-decision-detector.cjs +54 -54
  123. package/hooks/mindlore-dont-repeat.cjs +222 -222
  124. package/hooks/mindlore-fts5-sync.cjs +97 -88
  125. package/hooks/mindlore-index.cjs +229 -229
  126. package/hooks/mindlore-model-router.cjs +54 -54
  127. package/hooks/mindlore-post-compact.cjs +69 -69
  128. package/hooks/mindlore-post-read.cjs +106 -106
  129. package/hooks/mindlore-pre-compact.cjs +154 -154
  130. package/hooks/mindlore-read-guard.cjs +105 -105
  131. package/hooks/mindlore-research-guard.cjs +176 -176
  132. package/hooks/mindlore-search.cjs +200 -200
  133. package/hooks/mindlore-session-end.cjs +509 -523
  134. package/hooks/mindlore-session-focus.cjs +256 -245
  135. package/package.json +75 -78
  136. package/plugin.json +1 -1
  137. package/skills/mindlore-diary/SKILL.md +85 -85
  138. package/skills/mindlore-evolve/SKILL.md +126 -126
  139. package/skills/mindlore-explore/SKILL.md +109 -109
  140. package/skills/mindlore-ingest/SKILL.md +195 -195
  141. package/skills/mindlore-maintain/SKILL.md +125 -125
  142. package/skills/mindlore-query/SKILL.md +151 -151
  143. package/skills/mindlore-reflect/SKILL.md +141 -131
  144. package/skills/mindlore-stats/SKILL.md +106 -106
  145. package/templates/INDEX.md +14 -14
  146. package/templates/SCHEMA.md +292 -292
  147. package/templates/config.json +1 -1
  148. package/templates/extraction/article.md +15 -15
  149. package/templates/extraction/changelog.md +15 -15
  150. package/templates/extraction/default.md +15 -15
  151. package/templates/extraction/docs.md +15 -15
  152. package/templates/extraction/github-repo.md +17 -17
  153. package/dist/scripts/lib/daemon.d.ts +0 -16
  154. package/dist/scripts/lib/daemon.d.ts.map +0 -1
  155. package/dist/scripts/lib/daemon.js +0 -133
  156. package/dist/scripts/lib/daemon.js.map +0 -1
  157. package/dist/scripts/lib/embedding.d.ts +0 -5
  158. package/dist/scripts/lib/embedding.d.ts.map +0 -1
  159. package/dist/scripts/lib/embedding.js +0 -44
  160. package/dist/scripts/lib/embedding.js.map +0 -1
  161. package/dist/scripts/mindlore-daemon.d.ts +0 -2
  162. package/dist/scripts/mindlore-daemon.d.ts.map +0 -1
  163. package/dist/scripts/mindlore-daemon.js +0 -117
  164. package/dist/scripts/mindlore-daemon.js.map +0 -1
  165. package/dist/tests/daemon-integration.test.d.ts +0 -2
  166. package/dist/tests/daemon-integration.test.d.ts.map +0 -1
  167. package/dist/tests/daemon-integration.test.js +0 -37
  168. package/dist/tests/daemon-integration.test.js.map +0 -1
  169. package/dist/tests/daemon.test.d.ts +0 -2
  170. package/dist/tests/daemon.test.d.ts.map +0 -1
  171. package/dist/tests/daemon.test.js +0 -187
  172. package/dist/tests/daemon.test.js.map +0 -1
  173. package/dist/tests/embedding-hf-integration.test.d.ts +0 -2
  174. package/dist/tests/embedding-hf-integration.test.d.ts.map +0 -1
  175. package/dist/tests/embedding-hf-integration.test.js +0 -52
  176. package/dist/tests/embedding-hf-integration.test.js.map +0 -1
  177. package/dist/tests/embedding.test.d.ts +0 -6
  178. package/dist/tests/embedding.test.d.ts.map +0 -1
  179. package/dist/tests/embedding.test.js +0 -71
  180. package/dist/tests/embedding.test.js.map +0 -1
  181. package/dist/tests/sqlite-vec-v12.test.d.ts +0 -2
  182. package/dist/tests/sqlite-vec-v12.test.d.ts.map +0 -1
  183. package/dist/tests/sqlite-vec-v12.test.js +0 -72
  184. package/dist/tests/sqlite-vec-v12.test.js.map +0 -1
@@ -1,154 +1,154 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mindlore-pre-compact — PreCompact hook
6
- *
7
- * Before context compaction:
8
- * 1. Ensure FTS5 index is up to date
9
- * 2. Write pre-compact episode to episodes/ and append log entry
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
- const { findMindloreDir, openDatabase, hookLog, withTelemetry, listSnapshots } = require('./lib/mindlore-common.cjs');
15
-
16
- function collectRecentEpisodes(baseDir) {
17
- try {
18
- const dbPath = path.join(baseDir, 'mindlore.db');
19
- const db = openDatabase(dbPath, { readonly: true });
20
- if (!db) return [];
21
- try {
22
- const episodes = db.prepare(
23
- "SELECT kind, summary FROM episodes WHERE created_at > datetime('now', '-4 hours') ORDER BY created_at DESC LIMIT 20"
24
- ).all();
25
- if (episodes.length === 0) return [];
26
- const grouped = {};
27
- for (const ep of episodes) {
28
- const kind = ep.kind || 'other';
29
- if (!grouped[kind]) grouped[kind] = [];
30
- grouped[kind].push(ep.summary);
31
- }
32
- const lines = ['## Session Episodes'];
33
- for (const [kind, items] of Object.entries(grouped)) {
34
- lines.push(`### ${kind}`);
35
- for (const item of items) lines.push(`- ${item}`);
36
- }
37
- return lines;
38
- } finally {
39
- db.close();
40
- }
41
- } catch (_err) {
42
- return [];
43
- }
44
- }
45
-
46
- function collectGitDiff() {
47
- try {
48
- const { execFileSync } = require('child_process');
49
- let diffStat = '';
50
- try {
51
- diffStat = execFileSync('git', ['diff', '--stat', 'HEAD'], { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
52
- } catch { diffStat = ''; }
53
- if (diffStat) return ['## Changed Files (uncommitted)', '```', diffStat, '```'];
54
- return [];
55
- } catch (_err) {
56
- return [];
57
- }
58
- }
59
-
60
- function getActivePlan() {
61
- try {
62
- const plansDir = path.join(process.cwd(), '.claude', 'plans');
63
- if (!fs.existsSync(plansDir)) return [];
64
- const plans = fs.readdirSync(plansDir).filter(f => f.endsWith('.md'));
65
- if (plans.length === 0) return [];
66
- const latestPlan = plans.sort().pop();
67
- return [`## Active Plan: ${latestPlan}`];
68
- } catch (_err) {
69
- return [];
70
- }
71
- }
72
-
73
- function main() {
74
- const baseDir = findMindloreDir();
75
- if (!baseDir) return;
76
-
77
- // Trigger FTS5 sync via the index script
78
- const indexScript = path.join(__dirname, '..', 'scripts', 'mindlore-fts5-index.cjs');
79
- if (fs.existsSync(indexScript)) {
80
- try {
81
- const { spawnSync } = require('child_process');
82
- spawnSync('node', [indexScript, baseDir], {
83
- timeout: 10000,
84
- stdio: 'pipe',
85
- windowsHide: true,
86
- });
87
- } catch (_err) {
88
- // Non-fatal — index might fail if better-sqlite3 not available
89
- }
90
- }
91
-
92
- const now = new Date();
93
- const iso = now.toISOString();
94
- const ts = iso.replace(/[:.]/g, '-');
95
-
96
- const episodesDir = path.join(baseDir, 'episodes');
97
- try {
98
- const episodePath = path.join(episodesDir, `pre-compact-${ts}.md`);
99
- const content = [
100
- '---',
101
- 'type: episode',
102
- 'subtype: pre-compact',
103
- `date: ${iso.slice(0, 10)}`,
104
- `project: ${path.basename(process.cwd())}`,
105
- '---',
106
- '',
107
- `Pre-compact snapshot at ${iso}.`,
108
- `Working directory: ${process.cwd()}`,
109
- ].join('\n');
110
- fs.writeFileSync(episodePath, content, 'utf8');
111
- } catch (_err) { /* episodes dir may not exist */ }
112
-
113
- // Append log entry
114
- const logPath = path.join(baseDir, 'log.md');
115
- try {
116
- const entry = `| ${iso.slice(0, 10)} | pre-compact | FTS5 flush before compaction |\n`;
117
- fs.appendFileSync(logPath, entry, 'utf8');
118
- } catch (_err) { /* log file may not exist */ }
119
-
120
- // Build compaction snapshot (#17)
121
- const diaryDir = path.join(baseDir, 'diary');
122
- try {
123
- const sections = [];
124
- sections.push(...collectRecentEpisodes(baseDir));
125
- sections.push(...collectGitDiff());
126
- sections.push(...getActivePlan());
127
-
128
- if (sections.length > 0) {
129
- const snapshotContent = [
130
- '---',
131
- 'type: compaction-snapshot',
132
- `date: ${iso.slice(0, 10)}`,
133
- `project: ${path.basename(process.cwd())}`,
134
- '---',
135
- '',
136
- ...sections,
137
- ].join('\n');
138
- fs.writeFileSync(path.join(diaryDir, `compaction-snapshot-${ts}.md`), snapshotContent);
139
- }
140
-
141
- const snapshots = listSnapshots(diaryDir).filter(f => f.startsWith('compaction-'));
142
- while (snapshots.length > 5) {
143
- const oldest = snapshots.shift();
144
- if (oldest) fs.unlinkSync(path.join(diaryDir, oldest));
145
- }
146
- } catch (_err) { /* snapshot is best-effort */ }
147
-
148
- process.stdout.write('[Mindlore: pre-compact FTS5 flush complete]\n');
149
- }
150
-
151
- withTelemetry('mindlore-pre-compact', main).catch(err => {
152
- hookLog('mindlore-pre-compact', 'error', err?.message ?? String(err));
153
- process.exit(0);
154
- });
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * mindlore-pre-compact — PreCompact hook
6
+ *
7
+ * Before context compaction:
8
+ * 1. Ensure FTS5 index is up to date
9
+ * 2. Write pre-compact episode to episodes/ and append log entry
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const { findMindloreDir, openDatabase, hookLog, withTelemetry, listSnapshots } = require('./lib/mindlore-common.cjs');
15
+
16
+ function collectRecentEpisodes(baseDir) {
17
+ try {
18
+ const dbPath = path.join(baseDir, 'mindlore.db');
19
+ const db = openDatabase(dbPath, { readonly: true });
20
+ if (!db) return [];
21
+ try {
22
+ const episodes = db.prepare(
23
+ "SELECT kind, summary FROM episodes WHERE created_at > datetime('now', '-4 hours') ORDER BY created_at DESC LIMIT 20"
24
+ ).all();
25
+ if (episodes.length === 0) return [];
26
+ const grouped = {};
27
+ for (const ep of episodes) {
28
+ const kind = ep.kind || 'other';
29
+ if (!grouped[kind]) grouped[kind] = [];
30
+ grouped[kind].push(ep.summary);
31
+ }
32
+ const lines = ['## Session Episodes'];
33
+ for (const [kind, items] of Object.entries(grouped)) {
34
+ lines.push(`### ${kind}`);
35
+ for (const item of items) lines.push(`- ${item}`);
36
+ }
37
+ return lines;
38
+ } finally {
39
+ db.close();
40
+ }
41
+ } catch (_err) {
42
+ return [];
43
+ }
44
+ }
45
+
46
+ function collectGitDiff() {
47
+ try {
48
+ const { execFileSync } = require('child_process');
49
+ let diffStat = '';
50
+ try {
51
+ diffStat = execFileSync('git', ['diff', '--stat', 'HEAD'], { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
52
+ } catch { diffStat = ''; }
53
+ if (diffStat) return ['## Changed Files (uncommitted)', '```', diffStat, '```'];
54
+ return [];
55
+ } catch (_err) {
56
+ return [];
57
+ }
58
+ }
59
+
60
+ function getActivePlan() {
61
+ try {
62
+ const plansDir = path.join(process.cwd(), '.claude', 'plans');
63
+ if (!fs.existsSync(plansDir)) return [];
64
+ const plans = fs.readdirSync(plansDir).filter(f => f.endsWith('.md'));
65
+ if (plans.length === 0) return [];
66
+ const latestPlan = plans.sort().pop();
67
+ return [`## Active Plan: ${latestPlan}`];
68
+ } catch (_err) {
69
+ return [];
70
+ }
71
+ }
72
+
73
+ function main() {
74
+ const baseDir = findMindloreDir();
75
+ if (!baseDir) return;
76
+
77
+ // Trigger FTS5 sync via the index script
78
+ const indexScript = path.join(__dirname, '..', 'scripts', 'mindlore-fts5-index.cjs');
79
+ if (fs.existsSync(indexScript)) {
80
+ try {
81
+ const { spawnSync } = require('child_process');
82
+ spawnSync('node', [indexScript, baseDir], {
83
+ timeout: 10000,
84
+ stdio: 'pipe',
85
+ windowsHide: true,
86
+ });
87
+ } catch (_err) {
88
+ // Non-fatal — index might fail if better-sqlite3 not available
89
+ }
90
+ }
91
+
92
+ const now = new Date();
93
+ const iso = now.toISOString();
94
+ const ts = iso.replace(/[:.]/g, '-');
95
+
96
+ const episodesDir = path.join(baseDir, 'episodes');
97
+ try {
98
+ const episodePath = path.join(episodesDir, `pre-compact-${ts}.md`);
99
+ const content = [
100
+ '---',
101
+ 'type: episode',
102
+ 'subtype: pre-compact',
103
+ `date: ${iso.slice(0, 10)}`,
104
+ `project: ${path.basename(process.cwd())}`,
105
+ '---',
106
+ '',
107
+ `Pre-compact snapshot at ${iso}.`,
108
+ `Working directory: ${process.cwd()}`,
109
+ ].join('\n');
110
+ fs.writeFileSync(episodePath, content, 'utf8');
111
+ } catch (_err) { /* episodes dir may not exist */ }
112
+
113
+ // Append log entry
114
+ const logPath = path.join(baseDir, 'log.md');
115
+ try {
116
+ const entry = `| ${iso.slice(0, 10)} | pre-compact | FTS5 flush before compaction |\n`;
117
+ fs.appendFileSync(logPath, entry, 'utf8');
118
+ } catch (_err) { /* log file may not exist */ }
119
+
120
+ // Build compaction snapshot (#17)
121
+ const diaryDir = path.join(baseDir, 'diary');
122
+ try {
123
+ const sections = [];
124
+ sections.push(...collectRecentEpisodes(baseDir));
125
+ sections.push(...collectGitDiff());
126
+ sections.push(...getActivePlan());
127
+
128
+ if (sections.length > 0) {
129
+ const snapshotContent = [
130
+ '---',
131
+ 'type: compaction-snapshot',
132
+ `date: ${iso.slice(0, 10)}`,
133
+ `project: ${path.basename(process.cwd())}`,
134
+ '---',
135
+ '',
136
+ ...sections,
137
+ ].join('\n');
138
+ fs.writeFileSync(path.join(diaryDir, `compaction-snapshot-${ts}.md`), snapshotContent);
139
+ }
140
+
141
+ const snapshots = listSnapshots(diaryDir).filter(f => f.startsWith('compaction-'));
142
+ while (snapshots.length > 5) {
143
+ const oldest = snapshots.shift();
144
+ if (oldest) fs.unlinkSync(path.join(diaryDir, oldest));
145
+ }
146
+ } catch (_err) { /* snapshot is best-effort */ }
147
+
148
+ process.stdout.write('[Mindlore: pre-compact FTS5 flush complete]\n');
149
+ }
150
+
151
+ withTelemetry('mindlore-pre-compact', main).catch(err => {
152
+ hookLog('mindlore-pre-compact', 'error', err?.message ?? String(err));
153
+ process.exit(0);
154
+ });
@@ -1,105 +1,105 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mindlore-read-guard — PreToolUse hook (if: "Read")
6
- *
7
- * Repeated-read detection: detects files read multiple times
8
- * in the same session and emits a soft warning.
9
- * Does NOT block (exit 0) — advisory only.
10
- *
11
- * Storage: .mindlore/diary/_session-reads.json
12
- * Cleanup: session-end hook writes stats to delta then deletes the file.
13
- */
14
-
15
- const fs = require('fs');
16
- const path = require('path');
17
- const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton, withTelemetrySync } = require('./lib/mindlore-common.cjs');
18
-
19
- function main() {
20
- const baseDir = findMindloreDir();
21
- if (!baseDir) return;
22
-
23
- const filePath = readHookStdin(['file_path', 'path']);
24
- if (!filePath) return;
25
-
26
- // Only track CWD-relative files, skip .mindlore/ internals
27
- const cwd = process.cwd();
28
- const resolved = path.resolve(filePath);
29
- if (!resolved.startsWith(cwd)) return;
30
- if (resolved.startsWith(path.resolve(baseDir))) return;
31
-
32
- // Load or create session reads tracker
33
- const diaryDir = path.join(baseDir, 'diary');
34
- if (!fs.existsSync(diaryDir)) {
35
- fs.mkdirSync(diaryDir, { recursive: true });
36
- }
37
-
38
- const readsPath = path.join(diaryDir, `_session-reads-${getProjectName()}.json`);
39
- let reads = {};
40
- if (fs.existsSync(readsPath)) {
41
- try {
42
- reads = JSON.parse(fs.readFileSync(readsPath, 'utf8'));
43
- } catch (_err) {
44
- reads = {};
45
- }
46
- }
47
-
48
- const normalizedPath = path.resolve(filePath);
49
- const existing = reads[normalizedPath];
50
-
51
- // Support both old format (number) and new format (object with tokens)
52
- let count, tokens;
53
- if (typeof existing === 'number') {
54
- count = existing + 1;
55
- tokens = 0;
56
- reads[normalizedPath] = { count, tokens: 0, chars: 0 };
57
- } else if (existing && typeof existing === 'object') {
58
- count = (existing.count || 0) + 1;
59
- tokens = existing.tokens || 0;
60
- existing.count = count;
61
- reads[normalizedPath] = existing;
62
- } else {
63
- count = 1;
64
- tokens = 0;
65
- reads[normalizedPath] = { count, tokens: 0, chars: 0 };
66
- }
67
-
68
- // Write updated reads
69
- fs.writeFileSync(readsPath, JSON.stringify(reads, null, 2), 'utf8');
70
-
71
- const basename = path.basename(filePath);
72
- const tokenInfo = tokens > 0 ? ` (~${tokens} token)` : '';
73
-
74
- // Block on 3+ repeated reads (exit 2 = block tool call)
75
- if (count >= 3) {
76
- const totalWaste = tokens > 0 ? ` Toplam israf: ~${tokens * (count - 1)} token.` : '';
77
- process.stderr.write(`[Mindlore BLOCK] ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Edit icin gerekiyorsa once degisikligini yap, sonra tekrar oku. Analiz icin ctx_execute_file kullan.`);
78
- process.exit(2);
79
- }
80
-
81
- // Warn on 2nd read (exit 0 = allow but warn)
82
- if (count > 1) {
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 */ }
96
- process.stdout.write(JSON.stringify({
97
- hookSpecificOutput: {
98
- hookEventName: 'PreToolUse',
99
- additionalContext: `[Mindlore: ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Bir sonraki okuma engellenecek — Edit gerekiyorsa simdi yap.]${skeletonSection}`
100
- }
101
- }));
102
- }
103
- }
104
-
105
- try { withTelemetrySync('mindlore-read-guard', main); } catch (err) { hookLog('read-guard', 'error', err?.message ?? String(err)); }
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * mindlore-read-guard — PreToolUse hook (if: "Read")
6
+ *
7
+ * Repeated-read detection: detects files read multiple times
8
+ * in the same session and emits a soft warning.
9
+ * Does NOT block (exit 0) — advisory only.
10
+ *
11
+ * Storage: .mindlore/diary/_session-reads.json
12
+ * Cleanup: session-end hook writes stats to delta then deletes the file.
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton, withTelemetrySync } = require('./lib/mindlore-common.cjs');
18
+
19
+ function main() {
20
+ const baseDir = findMindloreDir();
21
+ if (!baseDir) return;
22
+
23
+ const filePath = readHookStdin(['file_path', 'path']);
24
+ if (!filePath) return;
25
+
26
+ // Only track CWD-relative files, skip .mindlore/ internals
27
+ const cwd = process.cwd();
28
+ const resolved = path.resolve(filePath);
29
+ if (!resolved.startsWith(cwd)) return;
30
+ if (resolved.startsWith(path.resolve(baseDir))) return;
31
+
32
+ // Load or create session reads tracker
33
+ const diaryDir = path.join(baseDir, 'diary');
34
+ if (!fs.existsSync(diaryDir)) {
35
+ fs.mkdirSync(diaryDir, { recursive: true });
36
+ }
37
+
38
+ const readsPath = path.join(diaryDir, `_session-reads-${getProjectName()}.json`);
39
+ let reads = {};
40
+ if (fs.existsSync(readsPath)) {
41
+ try {
42
+ reads = JSON.parse(fs.readFileSync(readsPath, 'utf8'));
43
+ } catch (_err) {
44
+ reads = {};
45
+ }
46
+ }
47
+
48
+ const normalizedPath = path.resolve(filePath);
49
+ const existing = reads[normalizedPath];
50
+
51
+ // Support both old format (number) and new format (object with tokens)
52
+ let count, tokens;
53
+ if (typeof existing === 'number') {
54
+ count = existing + 1;
55
+ tokens = 0;
56
+ reads[normalizedPath] = { count, tokens: 0, chars: 0 };
57
+ } else if (existing && typeof existing === 'object') {
58
+ count = (existing.count || 0) + 1;
59
+ tokens = existing.tokens || 0;
60
+ existing.count = count;
61
+ reads[normalizedPath] = existing;
62
+ } else {
63
+ count = 1;
64
+ tokens = 0;
65
+ reads[normalizedPath] = { count, tokens: 0, chars: 0 };
66
+ }
67
+
68
+ // Write updated reads
69
+ fs.writeFileSync(readsPath, JSON.stringify(reads, null, 2), 'utf8');
70
+
71
+ const basename = path.basename(filePath);
72
+ const tokenInfo = tokens > 0 ? ` (~${tokens} token)` : '';
73
+
74
+ // Block on 3+ repeated reads (exit 2 = block tool call)
75
+ if (count >= 3) {
76
+ const totalWaste = tokens > 0 ? ` Toplam israf: ~${tokens * (count - 1)} token.` : '';
77
+ process.stderr.write(`[Mindlore BLOCK] ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Edit icin gerekiyorsa once degisikligini yap, sonra tekrar oku. Analiz icin ctx_execute_file kullan.`);
78
+ process.exit(2);
79
+ }
80
+
81
+ // Warn on 2nd read (exit 0 = allow but warn)
82
+ if (count > 1) {
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 */ }
96
+ process.stdout.write(JSON.stringify({
97
+ hookSpecificOutput: {
98
+ hookEventName: 'PreToolUse',
99
+ additionalContext: `[Mindlore: ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Bir sonraki okuma engellenecek — Edit gerekiyorsa simdi yap.]${skeletonSection}`
100
+ }
101
+ }));
102
+ }
103
+ }
104
+
105
+ try { withTelemetrySync('mindlore-read-guard', main); } catch (err) { hookLog('read-guard', 'error', err?.message ?? String(err)); }