mindlore 0.6.0 → 0.6.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 +20 -13
- package/SCHEMA.md +3 -2
- package/dist/scripts/cc-session-sync.d.ts +1 -0
- package/dist/scripts/cc-session-sync.d.ts.map +1 -1
- package/dist/scripts/cc-session-sync.js +55 -0
- package/dist/scripts/cc-session-sync.js.map +1 -1
- package/dist/scripts/fetch-raw.js +62 -2
- package/dist/scripts/fetch-raw.js.map +1 -1
- package/dist/scripts/init.js +92 -47
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +4 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +11 -1
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/daemon.d.ts +1 -0
- package/dist/scripts/lib/daemon.d.ts.map +1 -1
- package/dist/scripts/lib/daemon.js +1 -0
- package/dist/scripts/lib/daemon.js.map +1 -1
- package/dist/scripts/lib/decay.d.ts.map +1 -1
- package/dist/scripts/lib/decay.js +3 -0
- package/dist/scripts/lib/decay.js.map +1 -1
- package/dist/scripts/lib/episodes.d.ts +1 -1
- package/dist/scripts/lib/episodes.d.ts.map +1 -1
- package/dist/scripts/lib/episodes.js +1 -1
- package/dist/scripts/lib/episodes.js.map +1 -1
- package/dist/scripts/lib/hybrid-search.d.ts +1 -0
- package/dist/scripts/lib/hybrid-search.d.ts.map +1 -1
- package/dist/scripts/lib/hybrid-search.js +16 -1
- package/dist/scripts/lib/hybrid-search.js.map +1 -1
- package/dist/scripts/lib/migrations-v061.d.ts +3 -0
- package/dist/scripts/lib/migrations-v061.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v061.js +58 -0
- package/dist/scripts/lib/migrations-v061.js.map +1 -0
- package/dist/scripts/lib/migrations-v062.d.ts +3 -0
- package/dist/scripts/lib/migrations-v062.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v062.js +35 -0
- package/dist/scripts/lib/migrations-v062.js.map +1 -0
- package/dist/scripts/lib/session-payload.d.ts.map +1 -1
- package/dist/scripts/lib/session-payload.js +12 -0
- package/dist/scripts/lib/session-payload.js.map +1 -1
- package/dist/scripts/lib/triage.d.ts +18 -0
- package/dist/scripts/lib/triage.d.ts.map +1 -0
- package/dist/scripts/lib/triage.js +81 -0
- package/dist/scripts/lib/triage.js.map +1 -0
- package/dist/scripts/mindlore-daemon.js +1 -0
- package/dist/scripts/mindlore-daemon.js.map +1 -1
- package/dist/scripts/mindlore-doctor.d.ts +18 -0
- package/dist/scripts/mindlore-doctor.d.ts.map +1 -0
- package/dist/scripts/mindlore-doctor.js +243 -0
- package/dist/scripts/mindlore-doctor.js.map +1 -0
- package/dist/scripts/mindlore-fts5-index.js +16 -3
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/scripts/mindlore-fts5-search.js +12 -10
- package/dist/scripts/mindlore-fts5-search.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts +10 -0
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +26 -1
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/scripts/mindlore-perf.d.ts +22 -0
- package/dist/scripts/mindlore-perf.d.ts.map +1 -0
- package/dist/scripts/mindlore-perf.js +130 -0
- package/dist/scripts/mindlore-perf.js.map +1 -0
- package/dist/tests/compaction-snapshot.test.d.ts +2 -0
- package/dist/tests/compaction-snapshot.test.d.ts.map +1 -0
- package/dist/tests/compaction-snapshot.test.js +55 -0
- package/dist/tests/compaction-snapshot.test.js.map +1 -0
- package/dist/tests/decay.test.js +29 -0
- package/dist/tests/decay.test.js.map +1 -1
- package/dist/tests/diary.test.js +3 -3
- package/dist/tests/diary.test.js.map +1 -1
- package/dist/tests/doctor.test.d.ts +2 -0
- package/dist/tests/doctor.test.d.ts.map +1 -0
- package/dist/tests/doctor.test.js +82 -0
- package/dist/tests/doctor.test.js.map +1 -0
- package/dist/tests/fetch-raw.test.js +12 -5
- package/dist/tests/fetch-raw.test.js.map +1 -1
- package/dist/tests/fts5.test.js +28 -0
- package/dist/tests/fts5.test.js.map +1 -1
- package/dist/tests/health-check-memory.test.js +27 -0
- package/dist/tests/health-check-memory.test.js.map +1 -1
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +3 -1
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/hook-smoke.test.js +27 -0
- package/dist/tests/hook-smoke.test.js.map +1 -1
- package/dist/tests/hybrid-search.test.js +25 -0
- package/dist/tests/hybrid-search.test.js.map +1 -1
- package/dist/tests/init.test.js +20 -0
- package/dist/tests/init.test.js.map +1 -1
- package/dist/tests/migrations-v061.test.d.ts +2 -0
- package/dist/tests/migrations-v061.test.d.ts.map +1 -0
- package/dist/tests/migrations-v061.test.js +70 -0
- package/dist/tests/migrations-v061.test.js.map +1 -0
- package/dist/tests/migrations-v062.test.d.ts +2 -0
- package/dist/tests/migrations-v062.test.d.ts.map +1 -0
- package/dist/tests/migrations-v062.test.js +61 -0
- package/dist/tests/migrations-v062.test.js.map +1 -0
- package/dist/tests/nomination.test.js +1 -1
- package/dist/tests/savings.test.d.ts +2 -0
- package/dist/tests/savings.test.d.ts.map +1 -0
- package/dist/tests/savings.test.js +87 -0
- package/dist/tests/savings.test.js.map +1 -0
- package/dist/tests/session-focus.test.js +15 -0
- package/dist/tests/session-focus.test.js.map +1 -1
- package/dist/tests/session-summary.test.d.ts +2 -0
- package/dist/tests/session-summary.test.d.ts.map +1 -0
- package/dist/tests/session-summary.test.js +102 -0
- package/dist/tests/session-summary.test.js.map +1 -0
- package/dist/tests/telemetry-perf.test.d.ts +2 -0
- package/dist/tests/telemetry-perf.test.d.ts.map +1 -0
- package/dist/tests/telemetry-perf.test.js +65 -0
- package/dist/tests/telemetry-perf.test.js.map +1 -0
- package/dist/tests/triage.test.d.ts +2 -0
- package/dist/tests/triage.test.d.ts.map +1 -0
- package/dist/tests/triage.test.js +69 -0
- package/dist/tests/triage.test.js.map +1 -0
- package/hooks/lib/mindlore-common.cjs +54 -6
- package/hooks/mindlore-fts5-sync.cjs +10 -4
- package/hooks/mindlore-post-compact.cjs +23 -3
- package/hooks/mindlore-pre-compact.cjs +78 -3
- package/hooks/mindlore-search.cjs +20 -11
- package/hooks/mindlore-session-end.cjs +32 -19
- package/hooks/mindlore-session-focus.cjs +107 -72
- package/package.json +7 -4
- package/plugin.json +1 -1
- package/skills/mindlore-maintain/SKILL.md +1 -0
- package/templates/config.json +1 -1
|
@@ -154,6 +154,23 @@ const SQL_FTS_CREATE =
|
|
|
154
154
|
const SQL_FTS_INSERT =
|
|
155
155
|
'INSERT INTO mindlore_fts (path, slug, description, type, category, title, content, tags, quality, date_captured, project) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
|
156
156
|
|
|
157
|
+
const SQL_FTS_SESSIONS_CREATE =
|
|
158
|
+
"CREATE VIRTUAL TABLE IF NOT EXISTS mindlore_fts_sessions USING fts5(path, slug, description, type, category, title, content, tags, quality, date_captured, project)";
|
|
159
|
+
|
|
160
|
+
const SQL_FTS_SESSIONS_INSERT =
|
|
161
|
+
'INSERT INTO mindlore_fts_sessions (path, slug, description, type, category, title, content, tags, quality, date_captured, project) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
|
162
|
+
|
|
163
|
+
const SESSION_CATEGORIES = ['cc-subagent', 'cc-session'];
|
|
164
|
+
|
|
165
|
+
function isSessionCategory(category) {
|
|
166
|
+
return SESSION_CATEGORIES.includes(category);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const VERSION_RE = /v(\d+)\.(\d+)(?:\.(\d+))?/g;
|
|
170
|
+
function fixVersionTokens(query) {
|
|
171
|
+
return query.replace(VERSION_RE, (_m, a, b, c) => c ? `"v${a} ${b} ${c}"` : `"v${a} ${b}"`);
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
/**
|
|
158
175
|
* Insert a row into FTS5 using an object parameter (replaces positional args).
|
|
159
176
|
*/
|
|
@@ -330,7 +347,7 @@ CREATE TABLE IF NOT EXISTS episodes (
|
|
|
330
347
|
// ~625 tokens context budget for multi-session inject (~4 chars/token)
|
|
331
348
|
const MULTI_SESSION_TOKEN_CAP_CHARS = 2500;
|
|
332
349
|
|
|
333
|
-
const EPISODE_KINDS_CJS = ['session', 'decision', 'event', 'preference', 'learning', 'friction', 'discovery', 'nomination'];
|
|
350
|
+
const EPISODE_KINDS_CJS = ['session', 'decision', 'event', 'preference', 'learning', 'friction', 'discovery', 'nomination', 'session-summary'];
|
|
334
351
|
|
|
335
352
|
/**
|
|
336
353
|
* Valid episode statuses. CO-EVOLUTION: mirrors EPISODE_STATUSES in scripts/lib/episodes.ts
|
|
@@ -623,7 +640,7 @@ function resolveWin32Bin(name) {
|
|
|
623
640
|
if (process.platform === 'win32') {
|
|
624
641
|
try {
|
|
625
642
|
return require('child_process')
|
|
626
|
-
.execSync(`where ${name}`, { encoding: 'utf8', timeout: 3000 })
|
|
643
|
+
.execSync(`where ${name}`, { encoding: 'utf8', timeout: 3000, windowsHide: true })
|
|
627
644
|
.trim().split('\n')[0].trim();
|
|
628
645
|
} catch (_e) { /* fall through */ }
|
|
629
646
|
}
|
|
@@ -654,14 +671,20 @@ function _rotateFile(filePath, maxBytes, keepLines) {
|
|
|
654
671
|
|
|
655
672
|
let _telDirEnsured = false;
|
|
656
673
|
|
|
657
|
-
function _writeTelemetry(hookName, duration_ms, ok) {
|
|
674
|
+
function _writeTelemetry({ hookName, duration_ms, ok, extra }) {
|
|
658
675
|
try {
|
|
659
676
|
if (!_telDirEnsured) {
|
|
660
677
|
fs.mkdirSync(GLOBAL_MINDLORE_DIR, { recursive: true });
|
|
661
678
|
_telDirEnsured = true;
|
|
662
679
|
}
|
|
663
680
|
const telPath = path.join(GLOBAL_MINDLORE_DIR, 'telemetry.jsonl');
|
|
664
|
-
const
|
|
681
|
+
const entry = { ts: new Date().toISOString(), hook: hookName, duration_ms, ok };
|
|
682
|
+
if (extra && typeof extra === 'object') {
|
|
683
|
+
for (const key of ['inject_tokens', 'source_tokens', 'injected_tokens', 'full_read_tokens']) {
|
|
684
|
+
if (typeof extra[key] === 'number') entry[key] = extra[key];
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
const line = JSON.stringify(entry) + '\n';
|
|
665
688
|
_rotateFile(telPath, HOOK_LOG_MAX_BYTES, TELEMETRY_KEEP_LINES);
|
|
666
689
|
fs.appendFileSync(telPath, line);
|
|
667
690
|
} catch { /* silent — telemetry must never crash hook */ }
|
|
@@ -678,7 +701,8 @@ async function withTelemetry(hookName, fn) {
|
|
|
678
701
|
ok = false;
|
|
679
702
|
thrown = err;
|
|
680
703
|
}
|
|
681
|
-
|
|
704
|
+
const extra = (result && typeof result === 'object') ? result : undefined;
|
|
705
|
+
_writeTelemetry({ hookName, duration_ms: Date.now() - start, ok, extra });
|
|
682
706
|
if (thrown) throw thrown;
|
|
683
707
|
return result;
|
|
684
708
|
}
|
|
@@ -694,11 +718,28 @@ function withTelemetrySync(hookName, fn) {
|
|
|
694
718
|
ok = false;
|
|
695
719
|
thrown = err;
|
|
696
720
|
}
|
|
697
|
-
|
|
721
|
+
const extra = (result && typeof result === 'object') ? result : undefined;
|
|
722
|
+
_writeTelemetry({ hookName, duration_ms: Date.now() - start, ok, extra });
|
|
698
723
|
if (thrown) throw thrown;
|
|
699
724
|
return result;
|
|
700
725
|
}
|
|
701
726
|
|
|
727
|
+
function withTimeoutDb(db, sql, params = [], { timeoutMs = 3000, mode = 'all' } = {}) {
|
|
728
|
+
if (!db) return mode === 'get' ? undefined : [];
|
|
729
|
+
try {
|
|
730
|
+
db.pragma(`busy_timeout = ${timeoutMs}`);
|
|
731
|
+
const stmt = db.prepare(sql);
|
|
732
|
+
if (mode === 'get') {
|
|
733
|
+
return params.length > 0 ? stmt.get(...params) : stmt.get();
|
|
734
|
+
}
|
|
735
|
+
return params.length > 0 ? stmt.all(...params) : stmt.all();
|
|
736
|
+
} catch (err) {
|
|
737
|
+
hookLog('timeout', 'warn', `DB query timeout/error: ${err.message}`);
|
|
738
|
+
_writeTelemetry({ hookName: 'db_timeout', duration_ms: 0, ok: false });
|
|
739
|
+
return mode === 'get' ? undefined : [];
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
702
743
|
module.exports = {
|
|
703
744
|
MINDLORE_DIR,
|
|
704
745
|
GLOBAL_MINDLORE_DIR,
|
|
@@ -715,6 +756,11 @@ module.exports = {
|
|
|
715
756
|
readHookStdin,
|
|
716
757
|
SQL_FTS_CREATE,
|
|
717
758
|
SQL_FTS_INSERT,
|
|
759
|
+
SQL_FTS_SESSIONS_CREATE,
|
|
760
|
+
SQL_FTS_SESSIONS_INSERT,
|
|
761
|
+
SESSION_CATEGORIES,
|
|
762
|
+
isSessionCategory,
|
|
763
|
+
fixVersionTokens,
|
|
718
764
|
insertFtsRow,
|
|
719
765
|
extractHeadings,
|
|
720
766
|
requireDatabase,
|
|
@@ -763,6 +809,8 @@ module.exports = {
|
|
|
763
809
|
// Telemetry (v0.6.0)
|
|
764
810
|
withTelemetry,
|
|
765
811
|
withTelemetrySync,
|
|
812
|
+
// DB timeout wrapper (v0.6.1)
|
|
813
|
+
withTimeoutDb,
|
|
766
814
|
};
|
|
767
815
|
|
|
768
816
|
function isDaemonRunning(pidFile) {
|
|
@@ -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, resolveProject, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { MINDLORE_DIR, DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry, SQL_FTS_SESSIONS_INSERT, isSessionCategory } = require('./lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
function main() {
|
|
19
19
|
const filePath = readHookStdin(['path', 'file_path']);
|
|
@@ -39,6 +39,8 @@ function main() {
|
|
|
39
39
|
|
|
40
40
|
const getHash = db.prepare('SELECT content_hash FROM file_hashes WHERE path = ?');
|
|
41
41
|
const deleteFts = db.prepare('DELETE FROM mindlore_fts WHERE path = ?');
|
|
42
|
+
const deleteFtsSessions = db.prepare('DELETE FROM mindlore_fts_sessions WHERE path = ?');
|
|
43
|
+
const insertFtsSessions = db.prepare(SQL_FTS_SESSIONS_INSERT);
|
|
42
44
|
const upsertHash = db.prepare(`
|
|
43
45
|
INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
44
46
|
VALUES (?, ?, ?)
|
|
@@ -61,8 +63,14 @@ function main() {
|
|
|
61
63
|
|
|
62
64
|
const { meta, body } = parseFrontmatter(content);
|
|
63
65
|
const { slug, description, type, category, title, tags, quality, dateCaptured, project: ftsProject } = extractFtsMetadata(meta, body, file, baseDir);
|
|
66
|
+
const resolvedProject = resolveProject(ftsProject, file, project);
|
|
64
67
|
deleteFts.run(file);
|
|
65
|
-
|
|
68
|
+
deleteFtsSessions.run(file);
|
|
69
|
+
if (isSessionCategory(category)) {
|
|
70
|
+
insertFtsSessions.run(file, slug, description, type, category, title, body, tags, quality ?? null, dateCaptured ?? null, resolvedProject);
|
|
71
|
+
} else {
|
|
72
|
+
insertFtsRow(db, { path: file, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project: resolvedProject });
|
|
73
|
+
}
|
|
66
74
|
upsertHash.run(file, hash, now);
|
|
67
75
|
}
|
|
68
76
|
});
|
|
@@ -71,8 +79,6 @@ function main() {
|
|
|
71
79
|
db.close();
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
// FileChanged event stdout'u yutulur — log gerekiyorsa dosyaya yaz
|
|
75
|
-
// process.stdout.write kaldırıldı (kimse görmüyor)
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
withTelemetry('mindlore-fts5-sync', main).catch(err => {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
|
-
const { findMindloreDir, getLatestDelta, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
17
|
+
const { findMindloreDir, getLatestDelta, readConfig, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
function main() {
|
|
20
20
|
const baseDir = findMindloreDir();
|
|
@@ -29,8 +29,8 @@ function main() {
|
|
|
29
29
|
output.push(`[Mindlore INDEX (post-compact)]\n${content}`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
// Re-inject latest delta
|
|
33
32
|
const diaryDir = path.join(baseDir, 'diary');
|
|
33
|
+
|
|
34
34
|
const latestDelta = getLatestDelta(diaryDir);
|
|
35
35
|
if (latestDelta) {
|
|
36
36
|
const deltaContent = fs.readFileSync(latestDelta, 'utf8').trim();
|
|
@@ -38,8 +38,28 @@ function main() {
|
|
|
38
38
|
output.push(`[Mindlore Delta (post-compact): ${deltaName}]\n${deltaContent}`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
try {
|
|
42
|
+
const snapshots = fs.readdirSync(diaryDir)
|
|
43
|
+
.filter(f => f.startsWith('compaction-snapshot-'))
|
|
44
|
+
.sort();
|
|
45
|
+
if (snapshots.length > 0) {
|
|
46
|
+
const latestSnapshot = snapshots[snapshots.length - 1];
|
|
47
|
+
const snapshotContent = fs.readFileSync(
|
|
48
|
+
path.join(diaryDir, latestSnapshot), 'utf8'
|
|
49
|
+
).trim();
|
|
50
|
+
output.push(`[Mindlore Compaction Resume]\n${snapshotContent}`);
|
|
51
|
+
}
|
|
52
|
+
} catch (_err) { /* snapshot best-effort */ }
|
|
53
|
+
|
|
41
54
|
if (output.length > 0) {
|
|
42
|
-
|
|
55
|
+
const config = readConfig(baseDir);
|
|
56
|
+
const budgetConfig = config?.tokenBudget ?? {};
|
|
57
|
+
const maxInjectChars = (budgetConfig.sessionInject || 2000) * 4;
|
|
58
|
+
let joined = output.join('\n\n');
|
|
59
|
+
if (joined.length > maxInjectChars) {
|
|
60
|
+
joined = joined.slice(0, maxInjectChars) + '\n[...truncated by token budget]';
|
|
61
|
+
}
|
|
62
|
+
process.stdout.write(joined + '\n');
|
|
43
63
|
}
|
|
44
64
|
}
|
|
45
65
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
|
-
const { findMindloreDir, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
14
|
+
const { findMindloreDir, openDatabase, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
15
15
|
|
|
16
16
|
function main() {
|
|
17
17
|
const baseDir = findMindloreDir();
|
|
@@ -25,6 +25,7 @@ function main() {
|
|
|
25
25
|
spawnSync('node', [indexScript, baseDir], {
|
|
26
26
|
timeout: 10000,
|
|
27
27
|
stdio: 'pipe',
|
|
28
|
+
windowsHide: true,
|
|
28
29
|
});
|
|
29
30
|
} catch (_err) {
|
|
30
31
|
// Non-fatal — index might fail if better-sqlite3 not available
|
|
@@ -33,11 +34,10 @@ function main() {
|
|
|
33
34
|
|
|
34
35
|
const now = new Date();
|
|
35
36
|
const iso = now.toISOString();
|
|
37
|
+
const ts = iso.replace(/[:.]/g, '-');
|
|
36
38
|
|
|
37
|
-
// Write pre-compact episode
|
|
38
39
|
const episodesDir = path.join(baseDir, 'episodes');
|
|
39
40
|
try {
|
|
40
|
-
const ts = iso.replace(/[:.]/g, '-');
|
|
41
41
|
const episodePath = path.join(episodesDir, `pre-compact-${ts}.md`);
|
|
42
42
|
const content = [
|
|
43
43
|
'---',
|
|
@@ -60,6 +60,81 @@ function main() {
|
|
|
60
60
|
fs.appendFileSync(logPath, entry, 'utf8');
|
|
61
61
|
} catch (_err) { /* log file may not exist */ }
|
|
62
62
|
|
|
63
|
+
// Build compaction snapshot (#17)
|
|
64
|
+
const diaryDir = path.join(baseDir, 'diary');
|
|
65
|
+
try {
|
|
66
|
+
const sections = [];
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const dbPath = path.join(baseDir, 'mindlore.db');
|
|
70
|
+
const db = openDatabase(dbPath, { readonly: true });
|
|
71
|
+
if (db) {
|
|
72
|
+
try {
|
|
73
|
+
const episodes = db.prepare(
|
|
74
|
+
"SELECT kind, summary FROM episodes WHERE created_at > datetime('now', '-4 hours') ORDER BY created_at DESC LIMIT 20"
|
|
75
|
+
).all();
|
|
76
|
+
if (episodes.length > 0) {
|
|
77
|
+
const grouped = {};
|
|
78
|
+
for (const ep of episodes) {
|
|
79
|
+
const kind = ep.kind || 'other';
|
|
80
|
+
if (!grouped[kind]) grouped[kind] = [];
|
|
81
|
+
grouped[kind].push(ep.summary);
|
|
82
|
+
}
|
|
83
|
+
sections.push('## Session Episodes');
|
|
84
|
+
for (const [kind, items] of Object.entries(grouped)) {
|
|
85
|
+
sections.push(`### ${kind}`);
|
|
86
|
+
for (const item of items) sections.push(`- ${item}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
db.close();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (_err) { /* graceful skip */ }
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const { execSync } = require('child_process');
|
|
97
|
+
const diffStat = execSync('git diff --stat HEAD 2>/dev/null || echo ""', {
|
|
98
|
+
encoding: 'utf8', timeout: 2000, windowsHide: true,
|
|
99
|
+
}).trim();
|
|
100
|
+
if (diffStat) {
|
|
101
|
+
sections.push('## Changed Files (uncommitted)', '```', diffStat, '```');
|
|
102
|
+
}
|
|
103
|
+
} catch (_err) { /* no git */ }
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const plansDir = path.join(process.cwd(), '.claude', 'plans');
|
|
107
|
+
if (fs.existsSync(plansDir)) {
|
|
108
|
+
const plans = fs.readdirSync(plansDir).filter(f => f.endsWith('.md'));
|
|
109
|
+
if (plans.length > 0) {
|
|
110
|
+
const latestPlan = plans.sort().pop();
|
|
111
|
+
sections.push(`## Active Plan: ${latestPlan}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch (_err) { /* skip */ }
|
|
115
|
+
|
|
116
|
+
if (sections.length > 0) {
|
|
117
|
+
const snapshotContent = [
|
|
118
|
+
'---',
|
|
119
|
+
'type: compaction-snapshot',
|
|
120
|
+
`date: ${iso.slice(0, 10)}`,
|
|
121
|
+
`project: ${path.basename(process.cwd())}`,
|
|
122
|
+
'---',
|
|
123
|
+
'',
|
|
124
|
+
...sections,
|
|
125
|
+
].join('\n');
|
|
126
|
+
fs.writeFileSync(path.join(diaryDir, `compaction-snapshot-${ts}.md`), snapshotContent);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const snapshots = fs.readdirSync(diaryDir)
|
|
130
|
+
.filter(f => f.startsWith('compaction-snapshot-'))
|
|
131
|
+
.sort();
|
|
132
|
+
while (snapshots.length > 5) {
|
|
133
|
+
const oldest = snapshots.shift();
|
|
134
|
+
if (oldest) fs.unlinkSync(path.join(diaryDir, oldest));
|
|
135
|
+
}
|
|
136
|
+
} catch (_err) { /* snapshot is best-effort */ }
|
|
137
|
+
|
|
63
138
|
process.stdout.write('[Mindlore: pre-compact FTS5 flush complete]\n');
|
|
64
139
|
}
|
|
65
140
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { getAllDbs, openDatabase, extractHeadings, readHookStdin, extractKeywords, sanitizeKeyword, readConfig, loadSqliteVecCjs, hasVecTableCjs, hookLog, incrementRecallCount, getDaemonPortFile, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
13
|
+
const { getAllDbs, openDatabase, extractHeadings, readHookStdin, extractKeywords, sanitizeKeyword, readConfig, loadSqliteVecCjs, hasVecTableCjs, hookLog, incrementRecallCount, getDaemonPortFile, withTelemetry, fixVersionTokens } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
|
|
15
15
|
const { execFileSync } = require('child_process');
|
|
16
16
|
|
|
@@ -33,7 +33,7 @@ function requestEmbeddingSync(query) {
|
|
|
33
33
|
const clientScript = path.join(__dirname, '..', 'scripts', 'lib', 'daemon-client.js');
|
|
34
34
|
if (!fs.existsSync(clientScript)) return null;
|
|
35
35
|
const result = execFileSync(process.execPath, [clientScript, portFile, query, '300'], {
|
|
36
|
-
timeout: 500, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe']
|
|
36
|
+
timeout: 500, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true,
|
|
37
37
|
});
|
|
38
38
|
const parsed = JSON.parse(result.trim());
|
|
39
39
|
return parsed.type === 'embedding' ? parsed.embedding : null;
|
|
@@ -122,11 +122,21 @@ function searchDb(dbPath, keywords) {
|
|
|
122
122
|
const sanitized = keywords.map(sanitizeKeyword).filter(Boolean);
|
|
123
123
|
if (sanitized.length === 0) { db.close(); return results; }
|
|
124
124
|
|
|
125
|
-
const ftsQuery = sanitized.join(' OR ');
|
|
126
|
-
const
|
|
125
|
+
const ftsQuery = fixVersionTokens(sanitized.join(' OR '));
|
|
126
|
+
const project = path.basename(process.cwd());
|
|
127
|
+
|
|
128
|
+
// v0.6.1: Project-scoped search with global fallback
|
|
129
|
+
let rows = db.prepare(
|
|
127
130
|
`SELECT path, slug, description, category, title, tags, rank
|
|
128
|
-
FROM mindlore_fts WHERE mindlore_fts MATCH ? ORDER BY rank LIMIT ?`
|
|
129
|
-
).all(ftsQuery, MAX_RESULTS * 2);
|
|
131
|
+
FROM mindlore_fts WHERE project = ? AND mindlore_fts MATCH ? ORDER BY rank LIMIT ?`
|
|
132
|
+
).all(project, ftsQuery, MAX_RESULTS * 2);
|
|
133
|
+
|
|
134
|
+
if (rows.length === 0) {
|
|
135
|
+
rows = db.prepare(
|
|
136
|
+
`SELECT path, slug, description, category, title, tags, rank
|
|
137
|
+
FROM mindlore_fts WHERE mindlore_fts MATCH ? ORDER BY rank LIMIT ?`
|
|
138
|
+
).all(ftsQuery, MAX_RESULTS * 2);
|
|
139
|
+
}
|
|
130
140
|
|
|
131
141
|
for (const r of rows) {
|
|
132
142
|
results.push({
|
|
@@ -237,17 +247,16 @@ function main() {
|
|
|
237
247
|
let totalUsed = 0;
|
|
238
248
|
for (const r of relevant) {
|
|
239
249
|
if (totalUsed >= totalChars) break;
|
|
240
|
-
const meta = r.meta || {};
|
|
241
250
|
const relativePath = path.relative(r.baseDir, r.path).replace(/\\/g, '/');
|
|
242
251
|
|
|
243
252
|
const headings = r.headings || [];
|
|
244
253
|
|
|
245
|
-
const category =
|
|
246
|
-
const title =
|
|
247
|
-
const description =
|
|
254
|
+
const category = r.category || path.dirname(relativePath).split('/')[0];
|
|
255
|
+
const title = r.title || r.slug || path.basename(r.path, '.md');
|
|
256
|
+
const description = r.description || '';
|
|
248
257
|
|
|
249
258
|
const headingStr = headings.length > 0 ? `\nBasliklar: ${headings.join(', ')}` : '';
|
|
250
|
-
const tagsStr =
|
|
259
|
+
const tagsStr = r.tags ? `\nTags: ${r.tags}` : '';
|
|
251
260
|
const entry = `[Mindlore: ${category}/${title}] ${description}\nDosya: ${relativePath}${tagsStr}${headingStr}`;
|
|
252
261
|
const truncated = entry.slice(0, perResultChars);
|
|
253
262
|
totalUsed += truncated.length;
|
|
@@ -54,6 +54,7 @@ if (process.argv.includes('--worker')) {
|
|
|
54
54
|
execFileSync(nodeExe, [scriptPath, ...args], {
|
|
55
55
|
timeout: timeoutMs,
|
|
56
56
|
env: { ...process.env, MINDLORE_HOME: baseDir },
|
|
57
|
+
windowsHide: true,
|
|
57
58
|
});
|
|
58
59
|
hookLog('session-end', 'info', label + ' completed');
|
|
59
60
|
} catch (err) {
|
|
@@ -112,6 +113,7 @@ function getRecentGitInfo() {
|
|
|
112
113
|
encoding: 'utf8',
|
|
113
114
|
timeout: 5000,
|
|
114
115
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
116
|
+
windowsHide: true,
|
|
115
117
|
}).trim();
|
|
116
118
|
if (!raw) return { commits: [], changedFiles: [] };
|
|
117
119
|
|
|
@@ -219,6 +221,20 @@ function main() {
|
|
|
219
221
|
fs.appendFileSync(logPath, logEntry, 'utf8');
|
|
220
222
|
}
|
|
221
223
|
|
|
224
|
+
// Raw accumulation warning
|
|
225
|
+
try {
|
|
226
|
+
const rawDir = path.join(baseDir, 'raw');
|
|
227
|
+
const sourcesDir = path.join(baseDir, 'sources');
|
|
228
|
+
if (fs.existsSync(rawDir) && fs.existsSync(sourcesDir)) {
|
|
229
|
+
const rawFiles = fs.readdirSync(rawDir).filter(f => f.endsWith('.md'));
|
|
230
|
+
const sourceFiles = new Set(fs.readdirSync(sourcesDir).filter(f => f.endsWith('.md')));
|
|
231
|
+
const unpromoted = rawFiles.filter(f => !sourceFiles.has(f)).length;
|
|
232
|
+
if (unpromoted >= 5) {
|
|
233
|
+
process.stdout.write(`[Mindlore] ${unpromoted} raw dosya promote bekliyor — \`/mindlore-maintain triage\` ile listele\n`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
} catch (_err) { /* graceful skip */ }
|
|
237
|
+
|
|
222
238
|
// Heavy ops: detach into child process so CC can exit immediately.
|
|
223
239
|
// Fixes "Hook cancelled" when CC kills the hook before completion.
|
|
224
240
|
// See: https://github.com/anthropics/claude-code/issues/41577
|
|
@@ -234,6 +250,7 @@ function main() {
|
|
|
234
250
|
detached: true,
|
|
235
251
|
stdio: 'ignore',
|
|
236
252
|
cwd: process.cwd(),
|
|
253
|
+
windowsHide: true,
|
|
237
254
|
});
|
|
238
255
|
child.unref();
|
|
239
256
|
} catch (_err) {
|
|
@@ -433,29 +450,25 @@ function syncObsidian(baseDir) {
|
|
|
433
450
|
const destBase = path.join(vaultPath, 'mindlore');
|
|
434
451
|
let exported = 0;
|
|
435
452
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (!fs.existsSync(srcDir)) continue;
|
|
439
|
-
|
|
440
|
-
const destDir = path.join(destBase, dir);
|
|
453
|
+
function walkAndExport(srcDir, destDir) {
|
|
454
|
+
if (!fs.existsSync(srcDir)) return;
|
|
441
455
|
fs.mkdirSync(destDir, { recursive: true });
|
|
442
|
-
|
|
443
|
-
for (const file of fs.readdirSync(srcDir).filter(f => f.endsWith('.md') && !f.startsWith('_'))) {
|
|
444
|
-
if (exportMdFile(path.join(srcDir, file), path.join(destDir, file), convertFn)) exported++;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// One-level subdirectories (e.g. diary/mindlore/)
|
|
448
456
|
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
449
|
-
if (
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
457
|
+
if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
|
|
458
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
459
|
+
const destPath = path.join(destDir, entry.name);
|
|
460
|
+
if (entry.isDirectory()) {
|
|
461
|
+
walkAndExport(srcPath, destPath);
|
|
462
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
463
|
+
if (exportMdFile(srcPath, destPath, convertFn)) exported++;
|
|
455
464
|
}
|
|
456
465
|
}
|
|
457
466
|
}
|
|
458
467
|
|
|
468
|
+
for (const dir of EXPORT_DIRS) {
|
|
469
|
+
walkAndExport(path.join(baseDir, dir), path.join(destBase, dir));
|
|
470
|
+
}
|
|
471
|
+
|
|
459
472
|
for (const rootFile of ['INDEX.md', 'log.md']) {
|
|
460
473
|
const srcPath = path.join(baseDir, rootFile);
|
|
461
474
|
if (!fs.existsSync(srcPath)) continue;
|
|
@@ -490,7 +503,7 @@ function syncGlobalRepo() {
|
|
|
490
503
|
if (!fs.existsSync(gitDir)) return;
|
|
491
504
|
|
|
492
505
|
const git = resolveGitBin();
|
|
493
|
-
const execOpts = (timeout) => ({ cwd: gDir, encoding: 'utf8', timeout, stdio: 'pipe' });
|
|
506
|
+
const execOpts = (timeout) => ({ cwd: gDir, encoding: 'utf8', timeout, stdio: 'pipe', windowsHide: true });
|
|
494
507
|
|
|
495
508
|
// Check for changes
|
|
496
509
|
const status = execSync(`"${git}" status --porcelain`, execOpts(5000)).trim();
|
|
@@ -502,7 +515,7 @@ function syncGlobalRepo() {
|
|
|
502
515
|
|
|
503
516
|
// Push — graceful fail if no remote or offline
|
|
504
517
|
try {
|
|
505
|
-
execSync(`"${git}" push`, execOpts(
|
|
518
|
+
execSync(`"${git}" push`, execOpts(30000));
|
|
506
519
|
} catch (_pushErr) {
|
|
507
520
|
hookLog('session-end', 'warn', 'git push failed (offline?): ' + (_pushErr?.message ?? '').slice(0, 100));
|
|
508
521
|
}
|