mindlore 0.5.8 → 0.6.0
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 +14 -2
- package/agents/mindlore-assistant.md +26 -0
- package/agents/mindlore-librarian.md +27 -0
- package/agents/mindlore-researcher.md +28 -0
- package/dist/scripts/lib/backfill.d.ts.map +1 -1
- package/dist/scripts/lib/backfill.js +5 -18
- package/dist/scripts/lib/backfill.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +2 -0
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/contradiction.d.ts.map +1 -1
- package/dist/scripts/lib/contradiction.js +11 -20
- package/dist/scripts/lib/contradiction.js.map +1 -1
- package/dist/scripts/lib/embedding.js +4 -4
- package/dist/scripts/lib/embedding.js.map +1 -1
- package/dist/scripts/maintain-cleanup.d.ts +13 -0
- package/dist/scripts/maintain-cleanup.d.ts.map +1 -0
- package/dist/scripts/maintain-cleanup.js +93 -0
- package/dist/scripts/maintain-cleanup.js.map +1 -0
- package/dist/scripts/mindlore-fts5-index.js +3 -3
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/tests/embedding-hf-integration.test.d.ts +2 -0
- package/dist/tests/embedding-hf-integration.test.d.ts.map +1 -0
- package/dist/tests/embedding-hf-integration.test.js +52 -0
- package/dist/tests/embedding-hf-integration.test.js.map +1 -0
- package/dist/tests/embedding.test.d.ts +1 -1
- package/dist/tests/embedding.test.js +2 -2
- package/dist/tests/embedding.test.js.map +1 -1
- package/dist/tests/fts5.test.js +54 -0
- package/dist/tests/fts5.test.js.map +1 -1
- package/dist/tests/helpers/db.d.ts +16 -0
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +5 -1
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/maintain-cleanup.test.d.ts +2 -0
- package/dist/tests/maintain-cleanup.test.d.ts.map +1 -0
- package/dist/tests/maintain-cleanup.test.js +65 -0
- package/dist/tests/maintain-cleanup.test.js.map +1 -0
- package/dist/tests/quality-populate.test.js +10 -0
- package/dist/tests/quality-populate.test.js.map +1 -1
- package/dist/tests/sqlite-vec-v12.test.d.ts +2 -0
- package/dist/tests/sqlite-vec-v12.test.d.ts.map +1 -0
- package/dist/tests/sqlite-vec-v12.test.js +72 -0
- package/dist/tests/sqlite-vec-v12.test.js.map +1 -0
- package/dist/tests/telemetry.test.d.ts +2 -0
- package/dist/tests/telemetry.test.d.ts.map +1 -0
- package/dist/tests/telemetry.test.js +55 -0
- package/dist/tests/telemetry.test.js.map +1 -0
- package/hooks/lib/mindlore-common.cjs +76 -9
- package/hooks/mindlore-cwd-changed.cjs +2 -2
- package/hooks/mindlore-decision-detector.cjs +5 -2
- package/hooks/mindlore-dont-repeat.cjs +2 -2
- package/hooks/mindlore-fts5-sync.cjs +7 -4
- package/hooks/mindlore-index.cjs +8 -5
- package/hooks/mindlore-model-router.cjs +2 -2
- package/hooks/mindlore-post-compact.cjs +5 -2
- package/hooks/mindlore-post-read.cjs +2 -2
- package/hooks/mindlore-pre-compact.cjs +5 -2
- package/hooks/mindlore-read-guard.cjs +2 -2
- package/hooks/mindlore-research-guard.cjs +2 -2
- package/hooks/mindlore-search.cjs +5 -2
- package/hooks/mindlore-session-end.cjs +17 -8
- package/hooks/mindlore-session-focus.cjs +5 -2
- package/package.json +6 -4
- package/plugin.json +1 -1
- package/skills/mindlore-ingest/SKILL.md +27 -6
- package/templates/SCHEMA.md +106 -7
- package/templates/config.json +4 -1
|
@@ -62,6 +62,16 @@ function getProjectName() {
|
|
|
62
62
|
return path.basename(process.cwd());
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function resolveProject(ftsProject, filePath, cwdFallback) {
|
|
66
|
+
if (ftsProject) return ftsProject;
|
|
67
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
68
|
+
const sessionMatch = normalized.match(/raw\/sessions\/([^/]+)\//);
|
|
69
|
+
if (sessionMatch) return sessionMatch[1];
|
|
70
|
+
const diaryMatch = normalized.match(/diary\/([^/]+)\//);
|
|
71
|
+
if (diaryMatch) return diaryMatch[1];
|
|
72
|
+
return cwdFallback;
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
function getLatestDelta(diaryDir) {
|
|
66
76
|
if (!fs.existsSync(diaryDir)) return null;
|
|
67
77
|
|
|
@@ -131,7 +141,8 @@ function extractFtsMetadata(meta, body, filePath, baseDir) {
|
|
|
131
141
|
}
|
|
132
142
|
const quality = meta.quality !== undefined && meta.quality !== null ? meta.quality : null;
|
|
133
143
|
const dateCaptured = meta.date_captured || meta.date || null;
|
|
134
|
-
|
|
144
|
+
const project = meta.project || null;
|
|
145
|
+
return { slug, description, type, category, title, tags, quality, dateCaptured, project };
|
|
135
146
|
}
|
|
136
147
|
|
|
137
148
|
/**
|
|
@@ -629,6 +640,65 @@ const extractSkeleton = (() => {
|
|
|
629
640
|
}
|
|
630
641
|
})();
|
|
631
642
|
|
|
643
|
+
const TELEMETRY_KEEP_LINES = 200;
|
|
644
|
+
|
|
645
|
+
function _rotateFile(filePath, maxBytes, keepLines) {
|
|
646
|
+
try {
|
|
647
|
+
const stat = fs.statSync(filePath);
|
|
648
|
+
if (stat.size > maxBytes) {
|
|
649
|
+
const lines = fs.readFileSync(filePath, 'utf8').trim().split('\n');
|
|
650
|
+
fs.writeFileSync(filePath, lines.slice(-keepLines).join('\n') + '\n');
|
|
651
|
+
}
|
|
652
|
+
} catch { /* file may not exist yet */ }
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
let _telDirEnsured = false;
|
|
656
|
+
|
|
657
|
+
function _writeTelemetry(hookName, duration_ms, ok) {
|
|
658
|
+
try {
|
|
659
|
+
if (!_telDirEnsured) {
|
|
660
|
+
fs.mkdirSync(GLOBAL_MINDLORE_DIR, { recursive: true });
|
|
661
|
+
_telDirEnsured = true;
|
|
662
|
+
}
|
|
663
|
+
const telPath = path.join(GLOBAL_MINDLORE_DIR, 'telemetry.jsonl');
|
|
664
|
+
const line = JSON.stringify({ ts: new Date().toISOString(), hook: hookName, duration_ms, ok }) + '\n';
|
|
665
|
+
_rotateFile(telPath, HOOK_LOG_MAX_BYTES, TELEMETRY_KEEP_LINES);
|
|
666
|
+
fs.appendFileSync(telPath, line);
|
|
667
|
+
} catch { /* silent — telemetry must never crash hook */ }
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
async function withTelemetry(hookName, fn) {
|
|
671
|
+
const start = Date.now();
|
|
672
|
+
let ok = true;
|
|
673
|
+
let result;
|
|
674
|
+
let thrown;
|
|
675
|
+
try {
|
|
676
|
+
result = await fn();
|
|
677
|
+
} catch (err) {
|
|
678
|
+
ok = false;
|
|
679
|
+
thrown = err;
|
|
680
|
+
}
|
|
681
|
+
_writeTelemetry(hookName, Date.now() - start, ok);
|
|
682
|
+
if (thrown) throw thrown;
|
|
683
|
+
return result;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function withTelemetrySync(hookName, fn) {
|
|
687
|
+
const start = Date.now();
|
|
688
|
+
let ok = true;
|
|
689
|
+
let result;
|
|
690
|
+
let thrown;
|
|
691
|
+
try {
|
|
692
|
+
result = fn();
|
|
693
|
+
} catch (err) {
|
|
694
|
+
ok = false;
|
|
695
|
+
thrown = err;
|
|
696
|
+
}
|
|
697
|
+
_writeTelemetry(hookName, Date.now() - start, ok);
|
|
698
|
+
if (thrown) throw thrown;
|
|
699
|
+
return result;
|
|
700
|
+
}
|
|
701
|
+
|
|
632
702
|
module.exports = {
|
|
633
703
|
MINDLORE_DIR,
|
|
634
704
|
GLOBAL_MINDLORE_DIR,
|
|
@@ -653,6 +723,7 @@ module.exports = {
|
|
|
653
723
|
readConfig,
|
|
654
724
|
detectSchemaVersion,
|
|
655
725
|
getProjectName,
|
|
726
|
+
resolveProject,
|
|
656
727
|
DEFAULT_MODELS,
|
|
657
728
|
// Episodes (v0.4.1)
|
|
658
729
|
EPISODE_KINDS_CJS,
|
|
@@ -689,6 +760,9 @@ module.exports = {
|
|
|
689
760
|
isDaemonRunning,
|
|
690
761
|
getDaemonPortFile,
|
|
691
762
|
getDaemonPidFile,
|
|
763
|
+
// Telemetry (v0.6.0)
|
|
764
|
+
withTelemetry,
|
|
765
|
+
withTelemetrySync,
|
|
692
766
|
};
|
|
693
767
|
|
|
694
768
|
function isDaemonRunning(pidFile) {
|
|
@@ -789,14 +863,7 @@ function hookLog(hook, level, message) {
|
|
|
789
863
|
msg: message,
|
|
790
864
|
pid: process.pid,
|
|
791
865
|
});
|
|
792
|
-
|
|
793
|
-
try {
|
|
794
|
-
const stat = fs.statSync(logFile);
|
|
795
|
-
if (stat.size > HOOK_LOG_MAX_BYTES) {
|
|
796
|
-
const lines = fs.readFileSync(logFile, 'utf8').trim().split('\n');
|
|
797
|
-
fs.writeFileSync(logFile, lines.slice(-HOOK_LOG_KEEP_LINES).join('\n') + '\n');
|
|
798
|
-
}
|
|
799
|
-
} catch (_rotateErr) { /* file may not exist yet */ }
|
|
866
|
+
_rotateFile(logFile, HOOK_LOG_MAX_BYTES, HOOK_LOG_KEEP_LINES);
|
|
800
867
|
fs.appendFileSync(logFile, entry + '\n');
|
|
801
868
|
} catch (_err) {
|
|
802
869
|
// Best effort — never crash a hook for logging
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
-
const { findMindloreDir, globalDir, hookLog } = require('./lib/mindlore-common.cjs');
|
|
18
|
+
const { findMindloreDir, globalDir, hookLog, withTelemetry } = 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
|
-
|
|
57
|
+
withTelemetry('mindlore-cwd-changed', 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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
12
|
+
const { findMindloreDir, readHookStdin, hookLog, withTelemetry } = 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,7 @@ function main() {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
withTelemetry('mindlore-decision-detector', main).catch(err => {
|
|
52
|
+
hookLog('mindlore-decision-detector', 'error', err?.message ?? String(err));
|
|
53
|
+
process.exit(0);
|
|
54
|
+
});
|
|
@@ -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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
21
|
+
const { findMindloreDir, getProjectName, hookLog, withTelemetrySync } = 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
|
-
try { main
|
|
222
|
+
try { withTelemetrySync('mindlore-dont-repeat', 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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { MINDLORE_DIR, DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
function main() {
|
|
19
19
|
const filePath = readHookStdin(['path', 'file_path']);
|
|
@@ -60,9 +60,9 @@ function main() {
|
|
|
60
60
|
if (existing && existing.content_hash === hash) continue;
|
|
61
61
|
|
|
62
62
|
const { meta, body } = parseFrontmatter(content);
|
|
63
|
-
const { slug, description, type, category, title, tags, quality, dateCaptured } = extractFtsMetadata(meta, body, file, baseDir);
|
|
63
|
+
const { slug, description, type, category, title, tags, quality, dateCaptured, project: ftsProject } = extractFtsMetadata(meta, body, file, baseDir);
|
|
64
64
|
deleteFts.run(file);
|
|
65
|
-
insertFtsRow(db, { path: file, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project });
|
|
65
|
+
insertFtsRow(db, { path: file, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project: resolveProject(ftsProject, file, project) });
|
|
66
66
|
upsertHash.run(file, hash, now);
|
|
67
67
|
}
|
|
68
68
|
});
|
|
@@ -75,4 +75,7 @@ function main() {
|
|
|
75
75
|
// process.stdout.write kaldırıldı (kimse görmüyor)
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
withTelemetry('mindlore-fts5-sync', main).catch(err => {
|
|
79
|
+
hookLog('mindlore-fts5-sync', 'error', err?.message ?? String(err));
|
|
80
|
+
process.exit(0);
|
|
81
|
+
});
|
package/hooks/mindlore-index.cjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { MINDLORE_DIR, DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, globalDir, hookLog } = require('./lib/mindlore-common.cjs');
|
|
13
|
+
const { MINDLORE_DIR, DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, resolveProject, globalDir, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
|
|
15
15
|
function main() {
|
|
16
16
|
const filePath = readHookStdin(['path', 'file_path']);
|
|
@@ -77,12 +77,12 @@ function main() {
|
|
|
77
77
|
|
|
78
78
|
// Parse frontmatter for rich FTS5 columns
|
|
79
79
|
const { meta, body } = parseFrontmatter(content);
|
|
80
|
-
const { slug, description, type, category, title, tags, quality, dateCaptured } = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
80
|
+
const { slug, description, type, category, title, tags, quality, dateCaptured, project: ftsProject } = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
81
81
|
|
|
82
82
|
// Update FTS5 + hash atomically
|
|
83
83
|
const updateIndex = db.transaction(() => {
|
|
84
84
|
db.prepare('DELETE FROM mindlore_fts WHERE path = ?').run(filePath);
|
|
85
|
-
insertFtsRow(db, { path: filePath, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project: getProjectName() });
|
|
85
|
+
insertFtsRow(db, { path: filePath, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project: resolveProject(ftsProject, filePath, getProjectName()) });
|
|
86
86
|
db.prepare(
|
|
87
87
|
`INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
88
88
|
VALUES (?, ?, ?)
|
|
@@ -197,7 +197,7 @@ function catchUpScan(baseDir, dbPath) {
|
|
|
197
197
|
|
|
198
198
|
const update = db.transaction(() => {
|
|
199
199
|
db.prepare('DELETE FROM mindlore_fts WHERE path = ?').run(filePath);
|
|
200
|
-
insertFtsRow(db, { path: filePath, ...ftsData, project: getProjectName() });
|
|
200
|
+
insertFtsRow(db, { path: filePath, ...ftsData, project: resolveProject(ftsData.project, filePath, getProjectName()) });
|
|
201
201
|
db.prepare(
|
|
202
202
|
`INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
203
203
|
VALUES (?, ?, ?)
|
|
@@ -218,4 +218,7 @@ function catchUpScan(baseDir, dbPath) {
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
main(
|
|
221
|
+
withTelemetry('mindlore-index', main).catch(err => {
|
|
222
|
+
hookLog('mindlore-index', 'error', err?.message ?? String(err));
|
|
223
|
+
process.exit(0);
|
|
224
|
+
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
|
-
const { findMindloreDir, readConfig, DEFAULT_MODELS, hookLog } = require('./lib/mindlore-common.cjs');
|
|
9
|
+
const { findMindloreDir, readConfig, DEFAULT_MODELS, hookLog, withTelemetrySync } = 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
|
-
try { main
|
|
54
|
+
try { withTelemetrySync('mindlore-model-router', 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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
17
|
+
const { findMindloreDir, getLatestDelta, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
function main() {
|
|
20
20
|
const baseDir = findMindloreDir();
|
|
@@ -43,4 +43,7 @@ function main() {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
withTelemetry('mindlore-post-compact', main).catch(err => {
|
|
47
|
+
hookLog('mindlore-post-compact', 'error', err?.message ?? String(err));
|
|
48
|
+
process.exit(0);
|
|
49
|
+
});
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const { findMindloreDir, getProjectName, hookLog } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { findMindloreDir, getProjectName, hookLog, withTelemetry } = 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
|
-
|
|
106
|
+
withTelemetry('mindlore-post-read', 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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
14
|
+
const { findMindloreDir, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
15
15
|
|
|
16
16
|
function main() {
|
|
17
17
|
const baseDir = findMindloreDir();
|
|
@@ -63,4 +63,7 @@ function main() {
|
|
|
63
63
|
process.stdout.write('[Mindlore: pre-compact FTS5 flush complete]\n');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
withTelemetry('mindlore-pre-compact', main).catch(err => {
|
|
67
|
+
hookLog('mindlore-pre-compact', 'error', err?.message ?? String(err));
|
|
68
|
+
process.exit(0);
|
|
69
|
+
});
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
|
-
const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton } = require('./lib/mindlore-common.cjs');
|
|
17
|
+
const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton, withTelemetrySync } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
function main() {
|
|
20
20
|
const baseDir = findMindloreDir();
|
|
@@ -102,4 +102,4 @@ function main() {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
try { main
|
|
105
|
+
try { withTelemetrySync('mindlore-read-guard', 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, hookLog } = require('./lib/mindlore-common.cjs');
|
|
17
|
+
const { getAllDbs, requireDatabase, extractKeywords, sanitizeKeyword, hookLog, withTelemetrySync } = 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
|
|
@@ -173,4 +173,4 @@ function main() {
|
|
|
173
173
|
process.stdout.write(JSON.stringify(output));
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
try { main
|
|
176
|
+
try { withTelemetrySync('mindlore-research-guard', main); } catch (err) { hookLog('research-guard', '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 { getAllDbs, openDatabase, extractHeadings, readHookStdin, extractKeywords, sanitizeKeyword, readConfig, loadSqliteVecCjs, hasVecTableCjs, hookLog, incrementRecallCount, getDaemonPortFile } = require('./lib/mindlore-common.cjs');
|
|
13
|
+
const { getAllDbs, openDatabase, extractHeadings, readHookStdin, extractKeywords, sanitizeKeyword, readConfig, loadSqliteVecCjs, hasVecTableCjs, hookLog, incrementRecallCount, getDaemonPortFile, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
|
|
15
15
|
const { execFileSync } = require('child_process');
|
|
16
16
|
|
|
@@ -307,4 +307,7 @@ function main() {
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
|
|
310
|
+
withTelemetry('mindlore-search', main).catch(err => {
|
|
311
|
+
hookLog('mindlore-search', 'error', err?.message ?? String(err));
|
|
312
|
+
process.exit(0);
|
|
313
|
+
});
|
|
@@ -13,7 +13,7 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
15
|
const { execSync, execFileSync, spawn } = require('child_process');
|
|
16
|
-
const { findMindloreDir, globalDir, getProjectName, openDatabase, ensureEpisodesTable, hasEpisodesTable, insertBareEpisode, insertFtsRow, hookLog, SHARED_EXPORT_DIRS, resolveWin32Bin } = require('./lib/mindlore-common.cjs');
|
|
16
|
+
const { findMindloreDir, globalDir, getProjectName, openDatabase, ensureEpisodesTable, hasEpisodesTable, insertBareEpisode, insertFtsRow, hookLog, SHARED_EXPORT_DIRS, resolveWin32Bin, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
17
17
|
|
|
18
18
|
const EXPORT_DIRS = SHARED_EXPORT_DIRS;
|
|
19
19
|
|
|
@@ -369,19 +369,25 @@ function writeEpisodeFile(baseDir, project, commits, changedFiles, reads) {
|
|
|
369
369
|
fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
let _obsidianHelpersCache = undefined; // undefined = not yet attempted
|
|
372
373
|
/**
|
|
373
374
|
* Load obsidian-helpers from compiled dist (single source of truth for wikilink conversion).
|
|
374
375
|
* Returns null if helpers not available (e.g. dev environment without build).
|
|
376
|
+
* Result is cached — require() runs at most once per process.
|
|
375
377
|
*/
|
|
376
|
-
function
|
|
378
|
+
function getObsidianHelpers() {
|
|
379
|
+
if (_obsidianHelpersCache !== undefined) return _obsidianHelpersCache;
|
|
377
380
|
try {
|
|
378
|
-
// Resolve from package root (hooks/ is sibling to dist/)
|
|
379
381
|
const hookDir = __dirname;
|
|
380
382
|
const pkgRoot = path.dirname(hookDir);
|
|
381
383
|
const helpersPath = path.join(pkgRoot, 'dist', 'scripts', 'lib', 'obsidian-helpers.js');
|
|
382
|
-
|
|
383
|
-
return
|
|
384
|
-
} catch (
|
|
384
|
+
_obsidianHelpersCache = require(helpersPath);
|
|
385
|
+
return _obsidianHelpersCache;
|
|
386
|
+
} catch (err) {
|
|
387
|
+
if (process.env.MINDLORE_DEBUG === '1') {
|
|
388
|
+
process.stderr.write(`[mindlore] obsidian-helpers not available: ${err.message}\n`);
|
|
389
|
+
}
|
|
390
|
+
_obsidianHelpersCache = null;
|
|
385
391
|
return null;
|
|
386
392
|
}
|
|
387
393
|
}
|
|
@@ -419,7 +425,7 @@ function syncObsidian(baseDir) {
|
|
|
419
425
|
if (!vaultPath || typeof vaultPath !== 'string') return;
|
|
420
426
|
if (!fs.existsSync(vaultPath)) return;
|
|
421
427
|
|
|
422
|
-
const helpers =
|
|
428
|
+
const helpers = getObsidianHelpers();
|
|
423
429
|
// Fallback regex if helpers unavailable (strips path prefixes like the canonical version)
|
|
424
430
|
const convertFn = helpers?.convertToWikilinks
|
|
425
431
|
?? ((c) => c.replace(/\[([^\]]+)\]\((?:\.\.?\/)?(?:[\w-]+\/)*([^/)]+)\.md\)/g, '[[$2]]'));
|
|
@@ -503,5 +509,8 @@ function syncGlobalRepo() {
|
|
|
503
509
|
}
|
|
504
510
|
|
|
505
511
|
if (!process.argv.includes('--worker')) {
|
|
506
|
-
main(
|
|
512
|
+
withTelemetry('mindlore-session-end', main).catch(err => {
|
|
513
|
+
hookLog('mindlore-session-end', 'error', err?.message ?? String(err));
|
|
514
|
+
process.exit(0);
|
|
515
|
+
});
|
|
507
516
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
-
const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, isDaemonRunning, getDaemonPidFile } = require('./lib/mindlore-common.cjs');
|
|
13
|
+
const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, isDaemonRunning, getDaemonPidFile, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
|
|
15
15
|
function main() {
|
|
16
16
|
const baseDir = findMindloreDir();
|
|
@@ -166,4 +166,7 @@ function main() {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
main(
|
|
169
|
+
withTelemetry('mindlore-session-focus', main).catch(err => {
|
|
170
|
+
hookLog('mindlore-session-focus', 'error', err?.message ?? String(err));
|
|
171
|
+
process.exit(0);
|
|
172
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindlore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "AI-native knowledge system for Claude Code",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"search": "node dist/scripts/mindlore-fts5-search.js",
|
|
20
20
|
"quality": "node dist/scripts/quality-populate.js",
|
|
21
21
|
"fetch-raw": "node dist/scripts/fetch-raw.js",
|
|
22
|
-
"cc-sync": "node dist/scripts/cc-memory-bulk-sync.js"
|
|
22
|
+
"cc-sync": "node dist/scripts/cc-memory-bulk-sync.js",
|
|
23
|
+
"cleanup": "node dist/scripts/maintain-cleanup.js"
|
|
23
24
|
},
|
|
24
25
|
"keywords": [
|
|
25
26
|
"claude-code",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"node": ">=20.0.0"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"better-sqlite3": "^
|
|
49
|
+
"better-sqlite3": "^12.9.0",
|
|
49
50
|
"zod": "^4.3.6"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"@types/node": "^25.6.0",
|
|
55
56
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
56
57
|
"@typescript-eslint/parser": "^8.58.1",
|
|
57
|
-
"@
|
|
58
|
+
"@huggingface/transformers": "^4.2.0",
|
|
58
59
|
"eslint": "^10.2.0",
|
|
59
60
|
"globals": "^17.5.0",
|
|
60
61
|
"jest": "^30.3.0",
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"typescript": "^6.0.2"
|
|
64
65
|
},
|
|
65
66
|
"files": [
|
|
67
|
+
"agents/",
|
|
66
68
|
"dist/",
|
|
67
69
|
"hooks/",
|
|
68
70
|
"skills/",
|
package/plugin.json
CHANGED
|
@@ -21,16 +21,36 @@ Add a new knowledge source to the `.mindlore/` knowledge base.
|
|
|
21
21
|
|
|
22
22
|
## Scope
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- Never hardcode `.mindlore/` path — always resolve dynamically
|
|
24
|
+
Tüm ingest işlemleri global `~/.mindlore/` dizinine yazılır.
|
|
25
|
+
Proje ayrımı frontmatter'daki `project` alanı ile yapılır.
|
|
26
|
+
`raw/` altına proje bazlı klasörleme yapılmaz (session sync hariç).
|
|
27
|
+
Frontmatter'a `project: {CWD project adı}` otomatik eklenir.
|
|
29
28
|
|
|
30
29
|
## Trigger
|
|
31
30
|
|
|
32
31
|
User shares a URL, text, file, or says "kaynak ekle", "source ingest", "bu linki kaydet", "knowledge ingest".
|
|
33
32
|
|
|
33
|
+
## Multi-URL Support
|
|
34
|
+
|
|
35
|
+
Birden fazla URL verildiğinde (boşluk veya virgülle ayrılmış):
|
|
36
|
+
|
|
37
|
+
1. URL'leri parse et — boşluk veya virgülle split
|
|
38
|
+
2. Her URL için sırayla mevcut URL Mode pipeline'ını çalıştır:
|
|
39
|
+
- Fetch → raw/ yazımı → sources/ dönüşümü → INDEX.md güncelle → log → FTS5 sync
|
|
40
|
+
3. Her URL için ayrı `skill-memory` dedup kontrolü yap
|
|
41
|
+
4. Her URL sonrası 7-point quality gate uygula
|
|
42
|
+
5. Hata olan URL'yi raporla ama sonrakine devam et (fail-forward)
|
|
43
|
+
6. Tüm URL'ler bittikten sonra toplu rapor döndür:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{ "processed": 3, "failed": 0, "skipped": 1, "sources": ["slug1", "slug2", "slug3"] }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Örnek kullanım:
|
|
50
|
+
```
|
|
51
|
+
/mindlore-ingest https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html https://docs.aws.amazon.com/dynamodb/latest/developerguide/best-practices.html
|
|
52
|
+
```
|
|
53
|
+
|
|
34
54
|
## Modes
|
|
35
55
|
|
|
36
56
|
### URL Mode (v0.5.2 — Zero-Token Pipeline)
|
|
@@ -60,6 +80,7 @@ If URL already in the list, warn user: "This URL was ingested recently. Re-inges
|
|
|
60
80
|
3. **Write sources/ summary from truncated content:**
|
|
61
81
|
- Extract: title, description (first paragraph), key topics
|
|
62
82
|
- Generate frontmatter: slug, type: source, source_url, date_captured, tags, quality
|
|
83
|
+
- `project: {path.basename(process.cwd()) ile CWD'den alınan proje adı}`
|
|
63
84
|
- `source_type` is auto-detected from URL pattern (see Source Summary Format)
|
|
64
85
|
- Write to `$MINDLORE_DIR/sources/{slug}.md`
|
|
65
86
|
|
|
@@ -148,7 +169,7 @@ After every ingest, verify all 7 checkpoints before reporting success:
|
|
|
148
169
|
```
|
|
149
170
|
Eğer score > 0.7 olan sonuç varsa KULLANICIYA SOR: "Bu içerik '${slug}' ile benzer görünüyor. Yine de eklensin mi?"
|
|
150
171
|
Kullanıcı onaylarsa devam et, yoksa atla.
|
|
151
|
-
1. **raw/ file exists** — immutable capture written with frontmatter (slug, type, source_url)
|
|
172
|
+
1. **raw/ file exists** — immutable capture written with frontmatter (slug, type, source_url, project)
|
|
152
173
|
2. **sources/ summary exists** — processed summary with full frontmatter (slug, type, title, tags, quality, description)
|
|
153
174
|
3. **INDEX.md updated** — stats line incremented, Recent section has new entry
|
|
154
175
|
4. **Domain updated** — if relevant domain exists, new finding added (max 1 domain per ingest)
|