mindlore 0.7.5 → 0.7.7
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +3 -3
- package/README.md +3 -1
- package/dist/scripts/bundle-hooks.js +5 -1
- package/dist/scripts/bundle-hooks.js.map +1 -1
- package/dist/scripts/init.js +49 -10
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +8 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +9 -1
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/db-helpers.d.ts +6 -0
- package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
- package/dist/scripts/lib/db-helpers.js +6 -0
- package/dist/scripts/lib/db-helpers.js.map +1 -1
- package/dist/scripts/lib/read-guard-core.d.ts +21 -0
- package/dist/scripts/lib/read-guard-core.d.ts.map +1 -0
- package/dist/scripts/lib/read-guard-core.js +40 -0
- package/dist/scripts/lib/read-guard-core.js.map +1 -0
- package/dist/scripts/lib/search-cache.d.ts +1 -7
- package/dist/scripts/lib/search-cache.d.ts.map +1 -1
- package/dist/scripts/lib/search-cache.js +3 -25
- package/dist/scripts/lib/search-cache.js.map +1 -1
- package/dist/scripts/lib/search-throttle.d.ts +10 -0
- package/dist/scripts/lib/search-throttle.d.ts.map +1 -0
- package/dist/scripts/lib/search-throttle.js +32 -0
- package/dist/scripts/lib/search-throttle.js.map +1 -0
- package/dist/scripts/lib/settings-cleanup.d.ts.map +1 -1
- package/dist/scripts/lib/settings-cleanup.js +2 -1
- package/dist/scripts/lib/settings-cleanup.js.map +1 -1
- package/dist/scripts/lib/setup-wizard.d.ts +13 -0
- package/dist/scripts/lib/setup-wizard.d.ts.map +1 -0
- package/dist/scripts/lib/setup-wizard.js +51 -0
- package/dist/scripts/lib/setup-wizard.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/decide-adapter.js +3 -3
- package/dist/scripts/lib/tool-adapters/decide-adapter.js.map +1 -1
- package/dist/scripts/lib/tool-adapters/get-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/get-adapter.js +10 -2
- package/dist/scripts/lib/tool-adapters/get-adapter.js.map +1 -1
- package/dist/scripts/lib/tool-adapters/ingest-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js +3 -3
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js.map +1 -1
- package/dist/scripts/lib/transcript-token-estimator.d.ts +8 -0
- package/dist/scripts/lib/transcript-token-estimator.d.ts.map +1 -0
- package/dist/scripts/lib/transcript-token-estimator.js +164 -0
- package/dist/scripts/lib/transcript-token-estimator.js.map +1 -0
- package/dist/scripts/maintain-cleanup.d.ts.map +1 -1
- package/dist/scripts/maintain-cleanup.js +2 -1
- package/dist/scripts/maintain-cleanup.js.map +1 -1
- package/dist/scripts/mcp-server.js +3 -3
- package/dist/scripts/mcp-server.js.map +1 -1
- package/dist/scripts/mindlore-backup.d.ts.map +1 -1
- package/dist/scripts/mindlore-backup.js +3 -2
- package/dist/scripts/mindlore-backup.js.map +1 -1
- package/dist/scripts/mindlore-clean-cache.d.ts +4 -1
- package/dist/scripts/mindlore-clean-cache.d.ts.map +1 -1
- package/dist/scripts/mindlore-clean-cache.js +47 -20
- package/dist/scripts/mindlore-clean-cache.js.map +1 -1
- package/dist/scripts/mindlore-doctor.d.ts +4 -0
- package/dist/scripts/mindlore-doctor.d.ts.map +1 -1
- package/dist/scripts/mindlore-doctor.js +9 -1
- package/dist/scripts/mindlore-doctor.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts +7 -0
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +57 -4
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/scripts/mindlore-learnings.d.ts +6 -0
- package/dist/scripts/mindlore-learnings.d.ts.map +1 -0
- package/dist/scripts/mindlore-learnings.js +106 -0
- package/dist/scripts/mindlore-learnings.js.map +1 -0
- package/dist/scripts/mindlore-obsidian.js +6 -5
- package/dist/scripts/mindlore-obsidian.js.map +1 -1
- package/dist/scripts/quality-populate.js +2 -1
- package/dist/scripts/quality-populate.js.map +1 -1
- package/dist/scripts/uninstall.js +2 -1
- package/dist/scripts/uninstall.js.map +1 -1
- package/dist/tests/clean-cache-eperm.test.d.ts +2 -0
- package/dist/tests/clean-cache-eperm.test.d.ts.map +1 -0
- package/dist/tests/clean-cache-eperm.test.js +74 -0
- package/dist/tests/clean-cache-eperm.test.js.map +1 -0
- package/dist/tests/doctor.test.js +18 -0
- package/dist/tests/doctor.test.js.map +1 -1
- package/dist/tests/health-check.test.d.ts +2 -0
- package/dist/tests/health-check.test.d.ts.map +1 -0
- package/dist/tests/health-check.test.js +61 -0
- package/dist/tests/health-check.test.js.map +1 -0
- package/dist/tests/helpers/db.d.ts +7 -2
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +16 -14
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/mindlore-ingest-extraction.test.d.ts +2 -0
- package/dist/tests/mindlore-ingest-extraction.test.d.ts.map +1 -0
- package/dist/tests/mindlore-ingest-extraction.test.js +48 -0
- package/dist/tests/mindlore-ingest-extraction.test.js.map +1 -0
- package/dist/tests/mindlore-learnings.test.d.ts +2 -0
- package/dist/tests/mindlore-learnings.test.d.ts.map +1 -0
- package/dist/tests/mindlore-learnings.test.js +63 -0
- package/dist/tests/mindlore-learnings.test.js.map +1 -0
- package/dist/tests/read-guard-perf.test.d.ts +2 -0
- package/dist/tests/read-guard-perf.test.d.ts.map +1 -0
- package/dist/tests/read-guard-perf.test.js +31 -0
- package/dist/tests/read-guard-perf.test.js.map +1 -0
- package/dist/tests/reflect-trigger.test.js +8 -1
- package/dist/tests/reflect-trigger.test.js.map +1 -1
- package/dist/tests/search-cache.test.js +0 -35
- package/dist/tests/search-cache.test.js.map +1 -1
- package/dist/tests/search-throttle.test.d.ts +2 -0
- package/dist/tests/search-throttle.test.d.ts.map +1 -0
- package/dist/tests/search-throttle.test.js +53 -0
- package/dist/tests/search-throttle.test.js.map +1 -0
- package/dist/tests/session-focus-reflect-nudge.test.js +3 -3
- package/dist/tests/session-focus-reflect-nudge.test.js.map +1 -1
- package/dist/tests/setup-wizard.test.d.ts +2 -0
- package/dist/tests/setup-wizard.test.d.ts.map +1 -0
- package/dist/tests/setup-wizard.test.js +35 -0
- package/dist/tests/setup-wizard.test.js.map +1 -0
- package/dist/tests/transcript-token-estimator.test.d.ts +2 -0
- package/dist/tests/transcript-token-estimator.test.d.ts.map +1 -0
- package/dist/tests/transcript-token-estimator.test.js +122 -0
- package/dist/tests/transcript-token-estimator.test.js.map +1 -0
- package/hooks/cc-memory-bulk-sync.cjs +9 -1
- package/hooks/cc-session-sync.cjs +9 -1
- package/hooks/lib/learnings-loader.cjs +21 -11
- package/hooks/lib/reflect-trigger.cjs +6 -3
- package/hooks/mindlore-cwd-changed.cjs +4 -5
- package/hooks/mindlore-dont-repeat.cjs +2 -1
- package/hooks/mindlore-post-read.cjs +2 -1
- package/hooks/mindlore-pre-compact.cjs +3 -2
- package/hooks/mindlore-read-guard.cjs +62 -35
- package/hooks/mindlore-search.cjs +231 -31
- package/hooks/mindlore-session-end.cjs +6 -8
- package/hooks/mindlore-session-focus.cjs +472 -23
- package/hooks/src/mindlore-cwd-changed.cjs +4 -5
- package/hooks/src/mindlore-dont-repeat.cjs +2 -1
- package/hooks/src/mindlore-post-read.cjs +2 -1
- package/hooks/src/mindlore-pre-compact.cjs +3 -2
- package/hooks/src/mindlore-read-guard.cjs +15 -55
- package/hooks/src/mindlore-search.cjs +39 -10
- package/hooks/src/mindlore-session-end.cjs +6 -8
- package/hooks/src/mindlore-session-focus.cjs +29 -21
- package/mcp-server.cjs +37944 -0
- package/package.json +4 -2
- package/plugin.json +6 -1
- package/skills/mindlore-ingest/SKILL.md +21 -0
- package/skills/mindlore-learnings/SKILL.md +30 -0
- package/start.cjs +141 -0
- package/templates/config.json +1 -1
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
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
4
|
const fs = require('fs');
|
|
16
5
|
const path = require('path');
|
|
17
6
|
const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton, withTelemetrySync } = require('./lib/mindlore-common.cjs');
|
|
7
|
+
const { safeMkdir, safeWriteFile } = require('./lib/secure-io.cjs');
|
|
8
|
+
const { runReadGuard } = require('../../dist/scripts/lib/read-guard-core.js');
|
|
18
9
|
|
|
19
10
|
function main() {
|
|
20
11
|
const baseDir = findMindloreDir();
|
|
@@ -23,64 +14,33 @@ function main() {
|
|
|
23
14
|
const filePath = readHookStdin(['file_path', 'path']);
|
|
24
15
|
if (!filePath) return;
|
|
25
16
|
|
|
26
|
-
// Only track CWD-relative files, skip .mindlore/ internals
|
|
27
17
|
const cwd = process.cwd();
|
|
28
18
|
const resolved = path.resolve(filePath);
|
|
29
19
|
if (!resolved.startsWith(cwd)) return;
|
|
30
20
|
if (resolved.startsWith(path.resolve(baseDir))) return;
|
|
31
21
|
|
|
32
|
-
// Load or create session reads tracker
|
|
33
22
|
const diaryDir = path.join(baseDir, 'diary');
|
|
34
|
-
|
|
35
|
-
fs.mkdirSync(diaryDir, { recursive: true });
|
|
36
|
-
}
|
|
23
|
+
safeMkdir(diaryDir);
|
|
37
24
|
|
|
38
25
|
const readsPath = path.join(diaryDir, `_session-reads-${getProjectName()}.json`);
|
|
39
26
|
let reads = {};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
27
|
+
try {
|
|
28
|
+
reads = JSON.parse(fs.readFileSync(readsPath, 'utf8'));
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.code !== 'ENOENT') hookLog('read-guard', 'warn', `read error: ${err.message}`);
|
|
31
|
+
reads = {};
|
|
46
32
|
}
|
|
47
33
|
|
|
48
|
-
const
|
|
49
|
-
|
|
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)` : '';
|
|
34
|
+
const decision = runReadGuard({ filePath: resolved, basename: path.basename(filePath) }, reads);
|
|
35
|
+
reads[resolved] = decision.updatedReadsEntry;
|
|
36
|
+
safeWriteFile(readsPath, JSON.stringify(reads, null, 2));
|
|
73
37
|
|
|
74
|
-
|
|
75
|
-
|
|
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.`);
|
|
38
|
+
if (decision.block) {
|
|
39
|
+
process.stderr.write(decision.warning);
|
|
78
40
|
process.exit(2);
|
|
79
41
|
}
|
|
80
42
|
|
|
81
|
-
|
|
82
|
-
if (count > 1) {
|
|
83
|
-
const totalWaste = tokens > 0 ? ` Toplam tekrar: ~${tokens * (count - 1)} token.` : '';
|
|
43
|
+
if (decision.additionalContext) {
|
|
84
44
|
let skeletonSection = '';
|
|
85
45
|
try {
|
|
86
46
|
const ext = path.extname(filePath).slice(1);
|
|
@@ -96,7 +56,7 @@ function main() {
|
|
|
96
56
|
process.stdout.write(JSON.stringify({
|
|
97
57
|
hookSpecificOutput: {
|
|
98
58
|
hookEventName: 'PreToolUse',
|
|
99
|
-
additionalContext:
|
|
59
|
+
additionalContext: decision.additionalContext + skeletonSection
|
|
100
60
|
}
|
|
101
61
|
}));
|
|
102
62
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const { getAllDbs, openDatabase, extractHeadings, readConfig, hookLog, incrementRecallCount, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
15
|
+
const { safeMkdir, safeWriteFile } = require('./lib/secure-io.cjs');
|
|
15
16
|
|
|
16
17
|
const MAX_RESULTS = 3;
|
|
17
18
|
const MIN_QUERY_WORDS = 3;
|
|
@@ -30,22 +31,42 @@ try {
|
|
|
30
31
|
// search-cache not built yet
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
let TokenEstimatorMod;
|
|
35
|
+
try {
|
|
36
|
+
TokenEstimatorMod = require('../dist/scripts/lib/transcript-token-estimator.js');
|
|
37
|
+
} catch (_err) {
|
|
38
|
+
// estimator not built yet
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
function parseStdin() {
|
|
34
42
|
try {
|
|
35
43
|
const raw = fs.readFileSync(0, 'utf8').trim();
|
|
36
|
-
if (!raw) return { userMessage: '', sessionId: 'unknown' };
|
|
44
|
+
if (!raw) return { userMessage: '', sessionId: 'unknown', transcriptPath: undefined };
|
|
37
45
|
const parsed = JSON.parse(raw);
|
|
38
46
|
const userMessage = parsed.prompt || parsed.content || parsed.message || parsed.query || raw;
|
|
39
47
|
const sessionId = parsed.session_id || 'unknown';
|
|
40
|
-
|
|
48
|
+
const transcriptPath = parsed.transcript_path || parsed.transcriptPath;
|
|
49
|
+
return { userMessage, sessionId, transcriptPath };
|
|
41
50
|
} catch (_err) {
|
|
42
|
-
return { userMessage: '', sessionId: 'unknown' };
|
|
51
|
+
return { userMessage: '', sessionId: 'unknown', transcriptPath: undefined };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getBaseMax(transcriptPath) {
|
|
56
|
+
if (TokenEstimatorMod) {
|
|
57
|
+
try {
|
|
58
|
+
return TokenEstimatorMod.adaptiveResultCount(transcriptPath);
|
|
59
|
+
} catch (_err) {
|
|
60
|
+
// fall through to default
|
|
61
|
+
}
|
|
43
62
|
}
|
|
63
|
+
return MAX_RESULTS;
|
|
44
64
|
}
|
|
45
65
|
|
|
46
66
|
function main() {
|
|
47
|
-
const { userMessage, sessionId } = parseStdin();
|
|
67
|
+
const { userMessage, sessionId, transcriptPath } = parseStdin();
|
|
48
68
|
if (!userMessage || userMessage.length < MIN_QUERY_WORDS) return;
|
|
69
|
+
const baseMax = getBaseMax(transcriptPath);
|
|
49
70
|
let searchMs = 0;
|
|
50
71
|
|
|
51
72
|
const dbPaths = getAllDbs();
|
|
@@ -61,18 +82,26 @@ function main() {
|
|
|
61
82
|
const synonyms = (config && config.synonyms) ? config.synonyms : {};
|
|
62
83
|
|
|
63
84
|
const allResults = [];
|
|
85
|
+
// Track tightest throttle cap across DBs — applied to the final result slice
|
|
86
|
+
// so cache hits (which return previously-stored arrays) still respect throttle
|
|
87
|
+
// state in subsequent calls of the same session.
|
|
88
|
+
let sessionEffectiveMax = baseMax;
|
|
64
89
|
for (const dbPath of dbPaths) {
|
|
65
90
|
const db = openDatabase(dbPath);
|
|
66
91
|
if (!db) continue;
|
|
67
92
|
try {
|
|
68
93
|
// Cache + throttle
|
|
69
94
|
let cache;
|
|
70
|
-
let effectiveMax =
|
|
95
|
+
let effectiveMax = baseMax;
|
|
71
96
|
if (SearchCacheMod) {
|
|
72
97
|
cache = new SearchCacheMod.SearchCache(db, { ttlMs: 300000 });
|
|
73
98
|
const throttle = new SearchCacheMod.SearchThrottle(db);
|
|
74
99
|
const callCount = throttle.incrementCallCount(sessionId);
|
|
75
|
-
|
|
100
|
+
// Throttle is baseMax-aware: when callCount <= 10 it returns baseMax,
|
|
101
|
+
// so adaptive expansion (up to 5 in low-context sessions) is honored.
|
|
102
|
+
// Above 10 calls it clamps to 1, above 20 to 0 (skip).
|
|
103
|
+
effectiveMax = throttle.getMaxResults(callCount, baseMax);
|
|
104
|
+
if (effectiveMax < sessionEffectiveMax) sessionEffectiveMax = effectiveMax;
|
|
76
105
|
if (effectiveMax === 0) {
|
|
77
106
|
hookLog('search', 'info', `Throttled (call #${callCount})`);
|
|
78
107
|
db.close();
|
|
@@ -81,7 +110,7 @@ function main() {
|
|
|
81
110
|
const cached = cache.get(userMessage);
|
|
82
111
|
if (cached) {
|
|
83
112
|
const baseDir = path.dirname(dbPath);
|
|
84
|
-
for (const r of cached) allResults.push({ ...r, baseDir });
|
|
113
|
+
for (const r of cached.slice(0, effectiveMax)) allResults.push({ ...r, baseDir });
|
|
85
114
|
db.close();
|
|
86
115
|
continue;
|
|
87
116
|
}
|
|
@@ -129,7 +158,7 @@ function main() {
|
|
|
129
158
|
|
|
130
159
|
// Sort by score descending, take top N
|
|
131
160
|
unique.sort((a, b) => b.score - a.score);
|
|
132
|
-
const relevant = unique.slice(0,
|
|
161
|
+
const relevant = unique.slice(0, sessionEffectiveMax);
|
|
133
162
|
if (relevant.length === 0) return;
|
|
134
163
|
|
|
135
164
|
// Token budget from config
|
|
@@ -172,7 +201,7 @@ function main() {
|
|
|
172
201
|
if (outputStr.length > OFFLOAD_THRESHOLD) {
|
|
173
202
|
const baseDir = path.dirname(dbPaths[0]);
|
|
174
203
|
const tmpDir = path.join(baseDir, 'tmp');
|
|
175
|
-
|
|
204
|
+
safeMkdir(tmpDir);
|
|
176
205
|
|
|
177
206
|
try {
|
|
178
207
|
const oneHourAgo = Date.now() - 3600000;
|
|
@@ -188,7 +217,7 @@ function main() {
|
|
|
188
217
|
} catch { /* cleanup is best-effort */ }
|
|
189
218
|
const fileName = `search-${Date.now()}.md`;
|
|
190
219
|
const filePath = path.join(tmpDir, fileName);
|
|
191
|
-
|
|
220
|
+
safeWriteFile(filePath, outputStr);
|
|
192
221
|
|
|
193
222
|
const summary = outputStr.slice(0, 500).replace(/\n/g, ' ').trim();
|
|
194
223
|
outputStr = `[Mindlore Search: ${outputStr.length} chars offloaded to ${filePath}]\n` +
|
|
@@ -13,7 +13,7 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
15
|
const { execFileSync, spawn } = require('child_process');
|
|
16
|
-
const { safeWriteFile, safeWriteJson } = require('
|
|
16
|
+
const { safeMkdir, safeWriteFile, safeWriteJson } = require('./lib/secure-io.cjs');
|
|
17
17
|
const { findMindloreDir, globalDir, getProjectName, openDatabase, ensureEpisodesTable, hasEpisodesTable, insertBareEpisode, insertFtsRow, hookLog, SHARED_EXPORT_DIRS, resolveWin32Bin, withTelemetry, getUnpromotedRawFiles, cleanupExpiredInjectLog } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
const EXPORT_DIRS = SHARED_EXPORT_DIRS;
|
|
@@ -151,9 +151,7 @@ function main() {
|
|
|
151
151
|
if (!baseDir) return;
|
|
152
152
|
|
|
153
153
|
const diaryDir = path.join(baseDir, 'diary');
|
|
154
|
-
|
|
155
|
-
fs.mkdirSync(diaryDir, { recursive: true });
|
|
156
|
-
}
|
|
154
|
+
safeMkdir(diaryDir);
|
|
157
155
|
|
|
158
156
|
const now = new Date();
|
|
159
157
|
const dateStr = formatDate(now);
|
|
@@ -323,7 +321,7 @@ function writeBareEpisode(baseDir, project, commits, changedFiles, reads) {
|
|
|
323
321
|
*/
|
|
324
322
|
function writeEpisodeFile(baseDir, project, commits, changedFiles, reads) {
|
|
325
323
|
const projDir = path.join(baseDir, 'diary', project || 'unknown');
|
|
326
|
-
|
|
324
|
+
safeMkdir(projDir);
|
|
327
325
|
|
|
328
326
|
const now = process.env.MINDLORE_EPISODE_TS ? new Date(process.env.MINDLORE_EPISODE_TS) : new Date();
|
|
329
327
|
const ts = formatDate(now);
|
|
@@ -406,7 +404,7 @@ function exportMdFile(srcPath, destPath, convertFn) {
|
|
|
406
404
|
}
|
|
407
405
|
let content = fs.readFileSync(srcPath, 'utf8');
|
|
408
406
|
content = convertFn(content);
|
|
409
|
-
|
|
407
|
+
safeWriteFile(destPath, content);
|
|
410
408
|
return true;
|
|
411
409
|
}
|
|
412
410
|
|
|
@@ -434,7 +432,7 @@ function syncObsidian(baseDir) {
|
|
|
434
432
|
|
|
435
433
|
function walkAndExport(srcDir, destDir) {
|
|
436
434
|
if (!fs.existsSync(srcDir)) return;
|
|
437
|
-
|
|
435
|
+
safeMkdir(destDir);
|
|
438
436
|
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
439
437
|
if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
|
|
440
438
|
const srcPath = path.join(srcDir, entry.name);
|
|
@@ -454,7 +452,7 @@ function syncObsidian(baseDir) {
|
|
|
454
452
|
for (const rootFile of ['INDEX.md', 'log.md']) {
|
|
455
453
|
const srcPath = path.join(baseDir, rootFile);
|
|
456
454
|
if (!fs.existsSync(srcPath)) continue;
|
|
457
|
-
|
|
455
|
+
safeMkdir(destBase);
|
|
458
456
|
if (exportMdFile(srcPath, path.join(destBase, rootFile), convertFn)) exported++;
|
|
459
457
|
}
|
|
460
458
|
|
|
@@ -12,7 +12,7 @@ const fs = require('fs');
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, withTelemetry, withTimeoutDb, listSnapshots, isCorruptionError, recoverCorruptDb, getNominationCounts, resolveMindloreHome } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
const { loadLearningsBlock } = require('./lib/learnings-loader.cjs');
|
|
15
|
-
const { shouldNudgeReflect } = require('../lib/reflect-trigger.cjs');
|
|
15
|
+
const { shouldNudgeReflect, buildNudgeMessage } = require('../lib/reflect-trigger.cjs');
|
|
16
16
|
|
|
17
17
|
function truncateSection(content, sectionRegex, keepCount, label) {
|
|
18
18
|
const match = content.match(sectionRegex);
|
|
@@ -138,10 +138,16 @@ function main() {
|
|
|
138
138
|
// Inject INDEX.md
|
|
139
139
|
const tIndex = Date.now();
|
|
140
140
|
const indexPath = path.join(baseDir, 'INDEX.md');
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
let indexContent;
|
|
142
|
+
try {
|
|
143
|
+
indexContent = fs.readFileSync(indexPath, 'utf8').trim();
|
|
144
|
+
} catch (err) {
|
|
145
|
+
if (err.code !== 'ENOENT') throw err;
|
|
146
|
+
indexContent = null;
|
|
147
|
+
}
|
|
148
|
+
if (indexContent !== null) {
|
|
149
|
+
sourceChars += indexContent.length;
|
|
150
|
+
output.push(`[Mindlore INDEX]\n${indexContent}`);
|
|
145
151
|
}
|
|
146
152
|
timings.index_read = Date.now() - tIndex;
|
|
147
153
|
|
|
@@ -181,15 +187,13 @@ function main() {
|
|
|
181
187
|
// Both are flat strings written by init — no JSON parse needed on session start
|
|
182
188
|
const versionPath = path.join(baseDir, '.version');
|
|
183
189
|
const pkgVersionPath = path.join(baseDir, '.pkg-version');
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
} catch (_err) { /* skip */ }
|
|
190
|
+
let installed;
|
|
191
|
+
try { installed = fs.readFileSync(versionPath, 'utf8').trim(); } catch (err) { if (err.code !== 'ENOENT') throw err; }
|
|
192
|
+
let pkgVersion;
|
|
193
|
+
try { pkgVersion = fs.readFileSync(pkgVersionPath, 'utf8').trim(); } catch (err) { if (err.code !== 'ENOENT') throw err; }
|
|
194
|
+
if (installed !== undefined && pkgVersion !== undefined && pkgVersion !== installed) {
|
|
195
|
+
output.push(`[Mindlore: Guncelleme mevcut (${installed} → ${pkgVersion}). \`npx mindlore init\` calistirin.]`);
|
|
196
|
+
}
|
|
193
197
|
timings.version_check = Date.now() - tVersion;
|
|
194
198
|
|
|
195
199
|
// v0.5.4: Consolidated session payload (replaces scattered episodes/activity/alerts injection)
|
|
@@ -220,14 +224,18 @@ function main() {
|
|
|
220
224
|
|
|
221
225
|
// Auto-reflect nudge (7-day threshold + 24h cooldown)
|
|
222
226
|
try {
|
|
223
|
-
const
|
|
224
|
-
"SELECT value FROM skill_memory WHERE skill_name = 'mindlore-reflect' AND key
|
|
225
|
-
).
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
const rows = db.prepare(
|
|
228
|
+
"SELECT key, value FROM skill_memory WHERE skill_name = 'mindlore-reflect' AND key IN ('last_reflect_date', 'last_nudge_date')"
|
|
229
|
+
).all();
|
|
230
|
+
const byKey = Object.fromEntries(rows.map(r => [r.key, r.value]));
|
|
231
|
+
const reflectRow = byKey['last_reflect_date'] ? { value: byKey['last_reflect_date'] } : undefined;
|
|
232
|
+
const nudgeRow = byKey['last_nudge_date'] ? { value: byKey['last_nudge_date'] } : undefined;
|
|
229
233
|
if (shouldNudgeReflect(reflectRow?.value ?? null, nudgeRow?.value ?? null, new Date())) {
|
|
230
|
-
|
|
234
|
+
const daysSince = reflectRow?.value ? Math.floor((Date.now() - new Date(reflectRow.value).getTime()) / 86400000) : 999;
|
|
235
|
+
const episodeCount = hasEpisodesTable(db) ? db.prepare("SELECT count(*) AS c FROM episodes").get()?.c ?? 0 : 0;
|
|
236
|
+
const diaryDirPath = path.join(baseDir, 'diary');
|
|
237
|
+
const diaryCount = fs.existsSync(diaryDirPath) ? fs.readdirSync(diaryDirPath).length : 0;
|
|
238
|
+
output.push(buildNudgeMessage({ daysSince, episodeCount, diaryCount }));
|
|
231
239
|
const nowIso = new Date().toISOString();
|
|
232
240
|
db.prepare(`
|
|
233
241
|
INSERT INTO skill_memory (skill_name, key, value, updated_at)
|