mindlore 0.6.9 → 0.7.1
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 +31 -4
- package/dist/scripts/bundle-hooks.d.ts +2 -0
- package/dist/scripts/bundle-hooks.d.ts.map +1 -0
- package/dist/scripts/bundle-hooks.js +68 -0
- package/dist/scripts/bundle-hooks.js.map +1 -0
- package/dist/scripts/cc-memory-bulk-sync.d.ts.map +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js +2 -1
- package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
- package/dist/scripts/cc-session-sync.d.ts.map +1 -1
- package/dist/scripts/cc-session-sync.js +3 -2
- package/dist/scripts/cc-session-sync.js.map +1 -1
- package/dist/scripts/init.js +4 -4
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +1 -2
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +2 -22
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/err-msg.d.ts +2 -0
- package/dist/scripts/lib/err-msg.d.ts.map +1 -0
- package/dist/scripts/lib/err-msg.js +7 -0
- package/dist/scripts/lib/err-msg.js.map +1 -0
- package/dist/scripts/lib/mcp-namespace.d.ts +2 -0
- package/dist/scripts/lib/mcp-namespace.d.ts.map +1 -0
- package/dist/scripts/lib/mcp-namespace.js +21 -0
- package/dist/scripts/lib/mcp-namespace.js.map +1 -0
- package/dist/scripts/lib/mcp-telemetry.d.ts +11 -0
- package/dist/scripts/lib/mcp-telemetry.d.ts.map +1 -0
- package/dist/scripts/lib/mcp-telemetry.js +37 -0
- package/dist/scripts/lib/mcp-telemetry.js.map +1 -0
- package/dist/scripts/lib/mcp-tools.d.ts +10 -0
- package/dist/scripts/lib/mcp-tools.d.ts.map +1 -0
- package/dist/scripts/lib/mcp-tools.js +121 -0
- package/dist/scripts/lib/mcp-tools.js.map +1 -0
- package/dist/scripts/lib/rrf.d.ts.map +1 -1
- package/dist/scripts/lib/rrf.js +2 -1
- package/dist/scripts/lib/rrf.js.map +1 -1
- package/dist/scripts/lib/search-engine.d.ts +1 -0
- package/dist/scripts/lib/search-engine.d.ts.map +1 -1
- package/dist/scripts/lib/search-engine.js +9 -5
- package/dist/scripts/lib/search-engine.js.map +1 -1
- package/dist/scripts/lib/slugify.d.ts +2 -0
- package/dist/scripts/lib/slugify.d.ts.map +1 -0
- package/dist/scripts/lib/slugify.js +13 -0
- package/dist/scripts/lib/slugify.js.map +1 -0
- package/dist/scripts/lib/smart-snippet.d.ts +9 -0
- package/dist/scripts/lib/smart-snippet.d.ts.map +1 -0
- package/dist/scripts/lib/smart-snippet.js +47 -0
- package/dist/scripts/lib/smart-snippet.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/brief-adapter.d.ts +15 -0
- package/dist/scripts/lib/tool-adapters/brief-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/brief-adapter.js +66 -0
- package/dist/scripts/lib/tool-adapters/brief-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.d.ts +31 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.js +71 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/ingest-adapter.d.ts +16 -0
- package/dist/scripts/lib/tool-adapters/ingest-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js +58 -0
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/recall-adapter.d.ts +20 -0
- package/dist/scripts/lib/tool-adapters/recall-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/recall-adapter.js +69 -0
- package/dist/scripts/lib/tool-adapters/recall-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.d.ts +22 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.js +32 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/stats-adapter.d.ts +15 -0
- package/dist/scripts/lib/tool-adapters/stats-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/stats-adapter.js +66 -0
- package/dist/scripts/lib/tool-adapters/stats-adapter.js.map +1 -0
- package/dist/scripts/maintain-cleanup.d.ts.map +1 -1
- package/dist/scripts/maintain-cleanup.js +3 -2
- package/dist/scripts/maintain-cleanup.js.map +1 -1
- package/dist/scripts/mcp-server.d.ts +3 -0
- package/dist/scripts/mcp-server.d.ts.map +1 -0
- package/dist/scripts/mcp-server.js +85 -0
- package/dist/scripts/mcp-server.js.map +1 -0
- package/dist/scripts/mindlore-doctor.d.ts.map +1 -1
- package/dist/scripts/mindlore-doctor.js +4 -6
- package/dist/scripts/mindlore-doctor.js.map +1 -1
- package/dist/scripts/mindlore-fts5-index.js +2 -2
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +2 -2
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/scripts/validate-manifest-cli.js +2 -2
- package/dist/scripts/validate-manifest-cli.js.map +1 -1
- package/dist/tests/err-msg.test.d.ts +2 -0
- package/dist/tests/err-msg.test.d.ts.map +1 -0
- package/dist/tests/err-msg.test.js +24 -0
- package/dist/tests/err-msg.test.js.map +1 -0
- package/dist/tests/hook-smoke.test.js +1 -1
- package/dist/tests/hook-smoke.test.js.map +1 -1
- package/dist/tests/manifest-v2.test.js +0 -7
- package/dist/tests/manifest-v2.test.js.map +1 -1
- package/dist/tests/mcp-server.test.d.ts +2 -0
- package/dist/tests/mcp-server.test.d.ts.map +1 -0
- package/dist/tests/mcp-server.test.js +118 -0
- package/dist/tests/mcp-server.test.js.map +1 -0
- package/dist/tests/mcp-tools.test.d.ts +2 -0
- package/dist/tests/mcp-tools.test.d.ts.map +1 -0
- package/dist/tests/mcp-tools.test.js +243 -0
- package/dist/tests/mcp-tools.test.js.map +1 -0
- package/dist/tests/search-hook.test.js +1 -1
- package/dist/tests/search-hook.test.js.map +1 -1
- package/dist/tests/smart-snippet.test.d.ts +2 -0
- package/dist/tests/smart-snippet.test.d.ts.map +1 -0
- package/dist/tests/smart-snippet.test.js +67 -0
- package/dist/tests/smart-snippet.test.js.map +1 -0
- package/hooks/cc-memory-bulk-sync.cjs +592 -0
- package/hooks/cc-session-sync.cjs +842 -0
- package/hooks/hooks.json +149 -0
- package/hooks/lib/mindlore-common.cjs +2 -2
- package/hooks/lib/secure-io.cjs +17 -0
- package/hooks/mindlore-cwd-changed.cjs +19 -34
- package/hooks/mindlore-decision-detector.cjs +40 -31
- package/hooks/mindlore-dont-repeat.cjs +57 -115
- package/hooks/mindlore-fts5-sync.cjs +15 -44
- package/hooks/mindlore-index.cjs +100 -101
- package/hooks/mindlore-model-router.cjs +20 -32
- package/hooks/mindlore-post-compact.cjs +26 -42
- package/hooks/mindlore-post-read.cjs +35 -60
- package/hooks/mindlore-pre-compact.cjs +55 -73
- package/hooks/mindlore-read-guard.cjs +28 -51
- package/hooks/mindlore-research-guard.cjs +63 -101
- package/hooks/mindlore-search.cjs +1142 -93
- package/hooks/mindlore-session-end.cjs +155 -276
- package/hooks/mindlore-session-focus.cjs +639 -110
- package/hooks/src/lib/constants.cjs +15 -0
- package/hooks/src/lib/mindlore-common.cjs +975 -0
- package/hooks/src/lib/mindlore-common.d.cts +72 -0
- package/hooks/src/lib/secure-io.cjs +17 -0
- package/hooks/src/lib/types.d.ts +58 -0
- package/hooks/src/mindlore-cwd-changed.cjs +57 -0
- package/hooks/src/mindlore-decision-detector.cjs +54 -0
- package/hooks/src/mindlore-dont-repeat.cjs +222 -0
- package/hooks/src/mindlore-fts5-sync.cjs +98 -0
- package/hooks/src/mindlore-index.cjs +230 -0
- package/hooks/src/mindlore-model-router.cjs +54 -0
- package/hooks/src/mindlore-post-compact.cjs +69 -0
- package/hooks/src/mindlore-post-read.cjs +106 -0
- package/hooks/src/mindlore-pre-compact.cjs +154 -0
- package/hooks/src/mindlore-read-guard.cjs +105 -0
- package/hooks/src/mindlore-research-guard.cjs +176 -0
- package/hooks/src/mindlore-search.cjs +200 -0
- package/hooks/src/mindlore-session-end.cjs +511 -0
- package/hooks/src/mindlore-session-focus.cjs +256 -0
- package/package.json +8 -3
- package/plugin.json +7 -1
- package/templates/config.json +1 -1
|
@@ -1,49 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* mindlore-fts5-sync — FileChanged hook (incremental re-index)
|
|
6
|
-
*
|
|
7
|
-
* Handles bulk file changes by checking all .mindlore/ .md files
|
|
8
|
-
* against their content hashes and re-indexing only changed ones.
|
|
9
|
-
*
|
|
10
|
-
* Lightweight complement to mindlore-index.cjs which handles single files.
|
|
11
|
-
* This hook catches cases where multiple files change at once (e.g., git pull).
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const fs = require('fs');
|
|
15
|
-
const path = require('path');
|
|
16
|
-
const { DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry, SQL_FTS_SESSIONS_INSERT, isSessionCategory, isInsideMindloreDir } = require('./lib/mindlore-common.cjs');
|
|
2
|
+
"use strict";
|
|
17
3
|
|
|
4
|
+
// hooks/src/mindlore-fts5-sync.cjs
|
|
5
|
+
var fs = require("fs");
|
|
6
|
+
var path = require("path");
|
|
7
|
+
var { DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry, SQL_FTS_SESSIONS_INSERT, isSessionCategory, isInsideMindloreDir } = require("./lib/mindlore-common.cjs");
|
|
18
8
|
function main() {
|
|
19
|
-
const filePath = readHookStdin([
|
|
20
|
-
|
|
9
|
+
const filePath = readHookStdin(["path", "file_path"]);
|
|
21
10
|
if (!filePath) return;
|
|
22
11
|
const resolved = path.resolve(filePath);
|
|
23
12
|
if (!isInsideMindloreDir(resolved)) return;
|
|
24
|
-
|
|
25
|
-
// Skip if this is a single .md file change — mindlore-index.cjs handles those.
|
|
26
|
-
// This hook is for bulk changes (git pull, manual batch edits).
|
|
27
|
-
if (filePath.endsWith('.md')) return;
|
|
28
|
-
|
|
13
|
+
if (filePath.endsWith(".md")) return;
|
|
29
14
|
const baseDir = getActiveMindloreDir();
|
|
30
15
|
if (!fs.existsSync(baseDir)) return;
|
|
31
|
-
|
|
32
16
|
const dbPath = path.join(baseDir, DB_NAME);
|
|
33
17
|
if (!fs.existsSync(dbPath)) return;
|
|
34
|
-
|
|
35
18
|
const db = openDatabase(dbPath);
|
|
36
19
|
if (!db) return;
|
|
37
|
-
|
|
38
20
|
const mdFiles = getAllMdFiles(baseDir);
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
for (const row of db.prepare('SELECT path, content_hash FROM file_hashes').all()) {
|
|
21
|
+
const allHashes = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const row of db.prepare("SELECT path, content_hash FROM file_hashes").all()) {
|
|
42
23
|
allHashes.set(row.path, row.content_hash);
|
|
43
24
|
}
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const deleteFtsSessions = db.prepare('DELETE FROM mindlore_fts_sessions WHERE path = ?');
|
|
25
|
+
const deleteFts = db.prepare("DELETE FROM mindlore_fts WHERE path = ?");
|
|
26
|
+
const deleteFtsSessions = db.prepare("DELETE FROM mindlore_fts_sessions WHERE path = ?");
|
|
47
27
|
const insertFtsSessions = db.prepare(SQL_FTS_SESSIONS_INSERT);
|
|
48
28
|
const upsertHash = db.prepare(`
|
|
49
29
|
INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
@@ -52,27 +32,20 @@ function main() {
|
|
|
52
32
|
content_hash = excluded.content_hash,
|
|
53
33
|
last_indexed = excluded.last_indexed
|
|
54
34
|
`);
|
|
55
|
-
|
|
56
|
-
const now = new Date().toISOString();
|
|
57
|
-
|
|
35
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
58
36
|
try {
|
|
59
37
|
const project = getProjectName();
|
|
60
|
-
|
|
61
38
|
const changedFiles = [];
|
|
62
39
|
for (const file of mdFiles) {
|
|
63
|
-
const content = fs.readFileSync(file,
|
|
40
|
+
const content = fs.readFileSync(file, "utf8").replace(/\r\n/g, "\n");
|
|
64
41
|
const hash = sha256(content);
|
|
65
|
-
|
|
66
42
|
const existingHash = allHashes.get(file);
|
|
67
43
|
if (existingHash === hash) continue;
|
|
68
|
-
|
|
69
44
|
const { meta, body } = parseFrontmatter(content);
|
|
70
45
|
const { slug, description, type, category, title, tags, quality, dateCaptured, project: ftsProject } = extractFtsMetadata(meta, body, file, baseDir);
|
|
71
46
|
const resolvedProject = resolveProject(ftsProject, file, project);
|
|
72
47
|
changedFiles.push({ file, hash, slug, description, type, category, title, tags, quality, dateCaptured, resolvedProject, body });
|
|
73
48
|
}
|
|
74
|
-
|
|
75
|
-
// No file I/O inside — minimize lock hold time
|
|
76
49
|
const transaction = db.transaction(() => {
|
|
77
50
|
for (const item of changedFiles) {
|
|
78
51
|
deleteFts.run(item.file);
|
|
@@ -89,10 +62,8 @@ function main() {
|
|
|
89
62
|
} finally {
|
|
90
63
|
db.close();
|
|
91
64
|
}
|
|
92
|
-
|
|
93
65
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
hookLog('mindlore-fts5-sync', 'error', err?.message ?? String(err));
|
|
66
|
+
withTelemetry("mindlore-fts5-sync", main).catch((err) => {
|
|
67
|
+
hookLog("mindlore-fts5-sync", "error", err?.message ?? String(err));
|
|
97
68
|
process.exit(0);
|
|
98
69
|
});
|
package/hooks/mindlore-index.cjs
CHANGED
|
@@ -1,92 +1,117 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
5
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// dist/scripts/lib/privacy-filter.js
|
|
9
|
+
var require_privacy_filter = __commonJS({
|
|
10
|
+
"dist/scripts/lib/privacy-filter.js"(exports2) {
|
|
11
|
+
"use strict";
|
|
12
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
13
|
+
exports2.DEFAULT_PATTERNS = void 0;
|
|
14
|
+
exports2.redactSecrets = redactSecrets;
|
|
15
|
+
var REPLACEMENT = "[REDACTED]";
|
|
16
|
+
var PATTERN_PREFIXES = [
|
|
17
|
+
{ prefix: "sk-", pattern: /sk-(?:proj-|ant-)?[A-Za-z0-9_-]{20,}/g },
|
|
18
|
+
{ prefix: "AKIA", pattern: /AKIA[0-9A-Z]{16}/g },
|
|
19
|
+
{ prefix: "ghp_", pattern: /ghp_[A-Za-z0-9]{36,}/g },
|
|
20
|
+
{ prefix: "gho_", pattern: /gho_[A-Za-z0-9]{36,}/g },
|
|
21
|
+
{ prefix: "github_pat_", pattern: /github_pat_[A-Za-z0-9_]{22,}/g },
|
|
22
|
+
{ prefix: "npm_", pattern: /npm_[A-Za-z0-9]{36,}/g },
|
|
23
|
+
{ prefix: "xox", pattern: /xox[bporas]-[A-Za-z0-9-]{10,}/g },
|
|
24
|
+
{ prefix: "eyJ", pattern: /eyJ[a-zA-Z0-9_\-]{20,}\.[a-zA-Z0-9_\-]{20,}\.[a-zA-Z0-9_\-]{20,}/g },
|
|
25
|
+
{ prefix: "AIza", pattern: /AIza[0-9A-Za-z_\-]{30,}/g },
|
|
26
|
+
{ prefix: "sk_live_", pattern: /sk_live_[a-zA-Z0-9]{20,}/g },
|
|
27
|
+
{ prefix: "pk_live_", pattern: /pk_live_[a-zA-Z0-9]{20,}/g },
|
|
28
|
+
{ prefix: "Bearer", pattern: /Bearer\s+[a-zA-Z0-9\-._~+/]+=*/g },
|
|
29
|
+
{ prefix: "-----BEGIN", pattern: /-----BEGIN\s(?:RSA\s|EC\s|DSA\s|OPENSSH\s)?PRIVATE\sKEY-----/g },
|
|
30
|
+
{ prefix: "Basic", pattern: /Basic\s+[a-zA-Z0-9+\/]{16,}={0,2}/g },
|
|
31
|
+
{ prefix: "-----BEGIN CERTIFICATE", pattern: /-----BEGIN\sCERTIFICATE-----/g }
|
|
32
|
+
];
|
|
33
|
+
var NO_PREFIX_PATTERNS = [
|
|
34
|
+
/(?:postgres|mysql|mongodb|redis|amqp)(?:\+srv)?:\/\/[^\s"']+/g,
|
|
35
|
+
/(?:PASSWORD|SECRET|TOKEN|API_KEY|PRIVATE_KEY|DATABASE_URL|DB_PASSWORD|AUTH_TOKEN|ACCESS_KEY|SECRET_KEY)=\S+/gi,
|
|
36
|
+
/(?:api_key|auth_token|access_token|refresh_token|client_secret|private_key|secret_key)\s*[:=]\s*["']?[^\s"',}{]{8,}["']?/gi
|
|
37
|
+
];
|
|
38
|
+
exports2.DEFAULT_PATTERNS = [
|
|
39
|
+
...PATTERN_PREFIXES.map((p) => p.pattern),
|
|
40
|
+
...NO_PREFIX_PATTERNS
|
|
41
|
+
];
|
|
42
|
+
function redactSecrets(text, extraPatterns) {
|
|
43
|
+
let result = text;
|
|
44
|
+
for (const { prefix, pattern } of PATTERN_PREFIXES) {
|
|
45
|
+
if (result.includes(prefix)) {
|
|
46
|
+
pattern.lastIndex = 0;
|
|
47
|
+
result = result.replace(pattern, REPLACEMENT);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const remaining = extraPatterns ? [...NO_PREFIX_PATTERNS, ...extraPatterns] : NO_PREFIX_PATTERNS;
|
|
51
|
+
for (const pattern of remaining) {
|
|
52
|
+
pattern.lastIndex = 0;
|
|
53
|
+
result = result.replace(pattern, REPLACEMENT);
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
15
59
|
|
|
60
|
+
// hooks/src/mindlore-index.cjs
|
|
61
|
+
var fs = require("fs");
|
|
62
|
+
var path = require("path");
|
|
63
|
+
var { safeMkdir, safeWriteFile } = require("./lib/secure-io.cjs");
|
|
64
|
+
var { DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, resolveProject, globalDir, hookLog, withTelemetry, isInsideMindloreDir, extractMindloreBaseDir } = require("./lib/mindlore-common.cjs");
|
|
16
65
|
function invalidateSearchCache(db) {
|
|
17
|
-
try {
|
|
66
|
+
try {
|
|
67
|
+
db.exec("DELETE FROM search_cache");
|
|
68
|
+
} catch (_) {
|
|
69
|
+
}
|
|
18
70
|
}
|
|
19
|
-
|
|
20
71
|
function main() {
|
|
21
|
-
const filePath = readHookStdin([
|
|
72
|
+
const filePath = readHookStdin(["path", "file_path"]);
|
|
22
73
|
if (!filePath) return;
|
|
23
|
-
|
|
24
|
-
// Only process .md files inside .mindlore/ (resolved path check prevents traversal)
|
|
25
|
-
if (!filePath.endsWith('.md')) return;
|
|
74
|
+
if (!filePath.endsWith(".md")) return;
|
|
26
75
|
const resolvedFile = path.resolve(filePath);
|
|
27
76
|
if (!isInsideMindloreDir(resolvedFile)) {
|
|
28
|
-
|
|
29
|
-
const isCcMemory = resolvedFile.includes(path.sep + '.claude' + path.sep + 'projects' + path.sep)
|
|
30
|
-
&& resolvedFile.includes(path.sep + 'memory' + path.sep)
|
|
31
|
-
&& resolvedFile.endsWith('.md');
|
|
77
|
+
const isCcMemory = resolvedFile.includes(path.sep + ".claude" + path.sep + "projects" + path.sep) && resolvedFile.includes(path.sep + "memory" + path.sep) && resolvedFile.endsWith(".md");
|
|
32
78
|
if (!isCcMemory) return;
|
|
33
|
-
|
|
34
|
-
// CC memory path — index to global mindlore DB
|
|
35
79
|
indexCcMemory(resolvedFile);
|
|
36
80
|
return;
|
|
37
81
|
}
|
|
38
|
-
|
|
39
82
|
const fileName = path.basename(filePath);
|
|
40
|
-
|
|
41
83
|
const baseDir = extractMindloreBaseDir(resolvedFile);
|
|
42
84
|
if (!baseDir) return;
|
|
43
85
|
const dbPath = path.join(baseDir, DB_NAME);
|
|
44
|
-
|
|
45
86
|
if (!fs.existsSync(dbPath)) return;
|
|
46
|
-
|
|
47
|
-
// Catch-up scan: when INDEX.md or log.md triggers, index recently-modified files
|
|
48
|
-
if (['INDEX.md', 'log.md'].includes(fileName)) {
|
|
87
|
+
if (["INDEX.md", "log.md"].includes(fileName)) {
|
|
49
88
|
catchUpScan(baseDir, dbPath);
|
|
50
89
|
return;
|
|
51
90
|
}
|
|
52
|
-
|
|
53
91
|
if (SKIP_FILES.has(fileName)) return;
|
|
54
|
-
|
|
55
92
|
if (!fs.existsSync(filePath)) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (!db) return;
|
|
93
|
+
const db2 = openDatabase(dbPath);
|
|
94
|
+
if (!db2) return;
|
|
59
95
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
invalidateSearchCache(
|
|
96
|
+
db2.prepare("DELETE FROM mindlore_fts WHERE path = ?").run(filePath);
|
|
97
|
+
db2.prepare("DELETE FROM file_hashes WHERE path = ?").run(filePath);
|
|
98
|
+
invalidateSearchCache(db2);
|
|
63
99
|
} finally {
|
|
64
|
-
|
|
100
|
+
db2.close();
|
|
65
101
|
}
|
|
66
102
|
return;
|
|
67
103
|
}
|
|
68
|
-
|
|
69
|
-
const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
104
|
+
const content = fs.readFileSync(filePath, "utf8").replace(/\r\n/g, "\n");
|
|
70
105
|
const hash = sha256(content);
|
|
71
|
-
|
|
72
106
|
const db = openDatabase(dbPath);
|
|
73
107
|
if (!db) return;
|
|
74
|
-
|
|
75
108
|
try {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.prepare('SELECT content_hash FROM file_hashes WHERE path = ?')
|
|
79
|
-
.get(filePath);
|
|
80
|
-
|
|
81
|
-
if (existing && existing.content_hash === hash) return; // Unchanged
|
|
82
|
-
|
|
83
|
-
// Parse frontmatter for rich FTS5 columns
|
|
109
|
+
const existing = db.prepare("SELECT content_hash FROM file_hashes WHERE path = ?").get(filePath);
|
|
110
|
+
if (existing && existing.content_hash === hash) return;
|
|
84
111
|
const { meta, body } = parseFrontmatter(content);
|
|
85
112
|
const { slug, description, type, category, title, tags, quality, dateCaptured, project: ftsProject } = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
86
|
-
|
|
87
|
-
// Update FTS5 + hash atomically
|
|
88
113
|
const updateIndex = db.transaction(() => {
|
|
89
|
-
db.prepare(
|
|
114
|
+
db.prepare("DELETE FROM mindlore_fts WHERE path = ?").run(filePath);
|
|
90
115
|
insertFtsRow(db, { path: filePath, slug, description, type, category, title, content: body, tags, quality, dateCaptured, project: resolveProject(ftsProject, filePath, getProjectName()) });
|
|
91
116
|
db.prepare(
|
|
92
117
|
`INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
@@ -94,7 +119,7 @@ function main() {
|
|
|
94
119
|
ON CONFLICT(path) DO UPDATE SET
|
|
95
120
|
content_hash = excluded.content_hash,
|
|
96
121
|
last_indexed = excluded.last_indexed`
|
|
97
|
-
).run(filePath, hash, new Date().toISOString());
|
|
122
|
+
).run(filePath, hash, (/* @__PURE__ */ new Date()).toISOString());
|
|
98
123
|
});
|
|
99
124
|
updateIndex();
|
|
100
125
|
invalidateSearchCache(db);
|
|
@@ -102,54 +127,39 @@ function main() {
|
|
|
102
127
|
db.close();
|
|
103
128
|
}
|
|
104
129
|
}
|
|
105
|
-
|
|
106
130
|
function indexCcMemory(filePath) {
|
|
107
|
-
const CC_MEMORY_CATEGORY =
|
|
108
|
-
// CC memory constants live in TS (scripts/lib/constants.ts) — CJS hooks can't require TS directly
|
|
131
|
+
const CC_MEMORY_CATEGORY = "cc-memory";
|
|
109
132
|
const globalBase = globalDir();
|
|
110
133
|
const dbPath = path.join(globalBase, DB_NAME);
|
|
111
|
-
|
|
112
|
-
const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
134
|
+
const content = fs.readFileSync(filePath, "utf8").replace(/\r\n/g, "\n");
|
|
113
135
|
if (!content.trim()) return;
|
|
114
|
-
|
|
115
|
-
// Privacy filter — redact secrets before DB write
|
|
116
136
|
let cleaned = content;
|
|
117
137
|
try {
|
|
118
|
-
const { redactSecrets } =
|
|
138
|
+
const { redactSecrets } = require_privacy_filter();
|
|
119
139
|
cleaned = redactSecrets(content);
|
|
120
140
|
} catch (_err) {
|
|
121
|
-
// privacy-filter not built — use raw content
|
|
122
141
|
}
|
|
123
|
-
|
|
124
|
-
// SHA256 dedup
|
|
125
142
|
const hash = sha256(cleaned);
|
|
126
143
|
const db = openDatabase(dbPath);
|
|
127
144
|
if (!db) return;
|
|
128
|
-
|
|
129
145
|
try {
|
|
130
|
-
const existing = db.prepare(
|
|
146
|
+
const existing = db.prepare("SELECT content_hash FROM file_hashes WHERE path = ?").get(filePath);
|
|
131
147
|
if (existing && existing.content_hash === hash) {
|
|
132
|
-
return;
|
|
148
|
+
return;
|
|
133
149
|
}
|
|
134
|
-
|
|
135
150
|
const { meta, body } = parseFrontmatter(cleaned);
|
|
136
|
-
const memType = String(meta.type ||
|
|
137
|
-
|
|
138
|
-
// Extract project scope from path: ~/.claude/projects/C--Users-X-proj/memory/
|
|
151
|
+
const memType = String(meta.type || "unknown");
|
|
139
152
|
const projMatch = filePath.match(/projects[/\\]([^/\\]+)[/\\]memory/);
|
|
140
153
|
const projectScope = projMatch ? projMatch[1] : null;
|
|
141
|
-
|
|
142
154
|
const ftsData = extractFtsMetadata(meta, body, filePath, globalBase);
|
|
143
|
-
|
|
144
|
-
// Update FTS5 + hash atomically
|
|
145
155
|
const updateIndex = db.transaction(() => {
|
|
146
|
-
db.prepare(
|
|
156
|
+
db.prepare("DELETE FROM mindlore_fts WHERE path = ?").run(filePath);
|
|
147
157
|
insertFtsRow(db, {
|
|
148
158
|
path: filePath,
|
|
149
159
|
...ftsData,
|
|
150
160
|
category: CC_MEMORY_CATEGORY,
|
|
151
161
|
type: memType,
|
|
152
|
-
project: projectScope
|
|
162
|
+
project: projectScope
|
|
153
163
|
});
|
|
154
164
|
db.prepare(
|
|
155
165
|
`INSERT INTO file_hashes (path, content_hash, last_indexed, source_type, project_scope)
|
|
@@ -159,12 +169,10 @@ function indexCcMemory(filePath) {
|
|
|
159
169
|
last_indexed = excluded.last_indexed,
|
|
160
170
|
source_type = excluded.source_type,
|
|
161
171
|
project_scope = excluded.project_scope`
|
|
162
|
-
).run(filePath, hash, new Date().toISOString(), CC_MEMORY_CATEGORY, projectScope);
|
|
172
|
+
).run(filePath, hash, (/* @__PURE__ */ new Date()).toISOString(), CC_MEMORY_CATEGORY, projectScope);
|
|
163
173
|
});
|
|
164
174
|
updateIndex();
|
|
165
|
-
|
|
166
|
-
// Copy to ~/.mindlore/memory/{project}/ for git-sync + obsidian
|
|
167
|
-
const memoryDir = path.join(globalBase, 'memory', projectScope || '_global');
|
|
175
|
+
const memoryDir = path.join(globalBase, "memory", projectScope || "_global");
|
|
168
176
|
safeMkdir(memoryDir);
|
|
169
177
|
const destPath = path.join(memoryDir, path.basename(filePath));
|
|
170
178
|
safeWriteFile(destPath, cleaned);
|
|
@@ -172,37 +180,29 @@ function indexCcMemory(filePath) {
|
|
|
172
180
|
db.close();
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
|
-
|
|
176
183
|
function catchUpScan(baseDir, dbPath) {
|
|
177
|
-
const CATCH_UP_DIRS = [
|
|
178
|
-
const fiveMinAgo = Date.now() - 5 * 60 *
|
|
179
|
-
|
|
184
|
+
const CATCH_UP_DIRS = ["raw", "sources", "analyses", "diary"];
|
|
185
|
+
const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
|
|
180
186
|
const db = openDatabase(dbPath);
|
|
181
187
|
if (!db) return;
|
|
182
|
-
|
|
183
188
|
try {
|
|
184
189
|
let indexed = 0;
|
|
185
190
|
for (const dir of CATCH_UP_DIRS) {
|
|
186
191
|
const dirPath = path.join(baseDir, dir);
|
|
187
192
|
if (!fs.existsSync(dirPath)) continue;
|
|
188
|
-
|
|
189
|
-
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.md'));
|
|
193
|
+
const files = fs.readdirSync(dirPath).filter((f) => f.endsWith(".md"));
|
|
190
194
|
for (const file of files) {
|
|
191
195
|
const filePath = path.join(dirPath, file);
|
|
192
196
|
const stat = fs.statSync(filePath);
|
|
193
197
|
if (stat.mtimeMs < fiveMinAgo) continue;
|
|
194
|
-
|
|
195
|
-
const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
198
|
+
const content = fs.readFileSync(filePath, "utf8").replace(/\r\n/g, "\n");
|
|
196
199
|
const hash = sha256(content);
|
|
197
|
-
|
|
198
|
-
const existing = db.prepare('SELECT content_hash FROM file_hashes WHERE path = ?').get(filePath);
|
|
200
|
+
const existing = db.prepare("SELECT content_hash FROM file_hashes WHERE path = ?").get(filePath);
|
|
199
201
|
if (existing && existing.content_hash === hash) continue;
|
|
200
|
-
|
|
201
202
|
const { meta, body } = parseFrontmatter(content);
|
|
202
203
|
const ftsData = extractFtsMetadata(meta, body, filePath, baseDir);
|
|
203
|
-
|
|
204
204
|
const update = db.transaction(() => {
|
|
205
|
-
db.prepare(
|
|
205
|
+
db.prepare("DELETE FROM mindlore_fts WHERE path = ?").run(filePath);
|
|
206
206
|
insertFtsRow(db, { path: filePath, ...ftsData, project: resolveProject(ftsData.project, filePath, getProjectName()) });
|
|
207
207
|
db.prepare(
|
|
208
208
|
`INSERT INTO file_hashes (path, content_hash, last_indexed)
|
|
@@ -210,7 +210,7 @@ function catchUpScan(baseDir, dbPath) {
|
|
|
210
210
|
ON CONFLICT(path) DO UPDATE SET
|
|
211
211
|
content_hash = excluded.content_hash,
|
|
212
212
|
last_indexed = excluded.last_indexed`
|
|
213
|
-
).run(filePath, hash, new Date().toISOString());
|
|
213
|
+
).run(filePath, hash, (/* @__PURE__ */ new Date()).toISOString());
|
|
214
214
|
});
|
|
215
215
|
update();
|
|
216
216
|
indexed++;
|
|
@@ -223,8 +223,7 @@ function catchUpScan(baseDir, dbPath) {
|
|
|
223
223
|
db.close();
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
hookLog('mindlore-index', 'error', err?.message ?? String(err));
|
|
226
|
+
withTelemetry("mindlore-index", main).catch((err) => {
|
|
227
|
+
hookLog("mindlore-index", "error", err?.message ?? String(err));
|
|
229
228
|
process.exit(0);
|
|
230
229
|
});
|
|
@@ -1,54 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* mindlore-model-router — PreToolUse (Agent) hook
|
|
5
|
-
* Overrides model for [mindlore:SKILL] marked Agent spawns.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const { findMindloreDir, readConfig, DEFAULT_MODELS, hookLog, withTelemetrySync } = require('./lib/mindlore-common.cjs');
|
|
10
|
-
|
|
11
|
-
const SKILL_KEYS = Object.keys(DEFAULT_MODELS).filter((k) => k !== 'default');
|
|
12
|
-
const MARKER_REGEX = new RegExp(`\\[mindlore:(${SKILL_KEYS.join('|')})\\]`);
|
|
1
|
+
"use strict";
|
|
13
2
|
|
|
3
|
+
// hooks/src/mindlore-model-router.cjs
|
|
4
|
+
var fs = require("fs");
|
|
5
|
+
var { findMindloreDir, readConfig, DEFAULT_MODELS, hookLog, withTelemetrySync } = require("./lib/mindlore-common.cjs");
|
|
6
|
+
var SKILL_KEYS = Object.keys(DEFAULT_MODELS).filter((k) => k !== "default");
|
|
7
|
+
var MARKER_REGEX = new RegExp(`\\[mindlore:(${SKILL_KEYS.join("|")})\\]`);
|
|
14
8
|
function main() {
|
|
15
9
|
const mindloreDir = findMindloreDir();
|
|
16
10
|
if (!mindloreDir) return;
|
|
17
|
-
|
|
18
11
|
let input;
|
|
19
12
|
try {
|
|
20
|
-
const raw = fs.readFileSync(0,
|
|
13
|
+
const raw = fs.readFileSync(0, "utf8").trim();
|
|
21
14
|
if (!raw) return;
|
|
22
15
|
input = JSON.parse(raw);
|
|
23
16
|
} catch (_err) {
|
|
24
17
|
return;
|
|
25
18
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (toolName !== 'Agent') return;
|
|
29
|
-
|
|
19
|
+
const toolName = input.tool_name || "";
|
|
20
|
+
if (toolName !== "Agent") return;
|
|
30
21
|
const toolInput = input.tool_input || {};
|
|
31
|
-
const prompt = toolInput.prompt ||
|
|
22
|
+
const prompt = toolInput.prompt || "";
|
|
32
23
|
const match = prompt.match(MARKER_REGEX);
|
|
33
24
|
if (!match) return;
|
|
34
|
-
|
|
35
25
|
const skill = match[1];
|
|
36
|
-
|
|
37
|
-
// Resolve model: config.json → config default → hardcoded
|
|
38
26
|
const config = readConfig(mindloreDir);
|
|
39
|
-
const models =
|
|
27
|
+
const models = config && config.models || {};
|
|
40
28
|
const model = models[skill] || models.default || DEFAULT_MODELS[skill] || DEFAULT_MODELS.default;
|
|
41
|
-
|
|
42
|
-
const updatedInput = { ...toolInput, model: model };
|
|
43
|
-
|
|
29
|
+
const updatedInput = { ...toolInput, model };
|
|
44
30
|
const output = {
|
|
45
31
|
hookSpecificOutput: {
|
|
46
|
-
hookEventName:
|
|
47
|
-
updatedInput
|
|
48
|
-
}
|
|
32
|
+
hookEventName: "PreToolUse",
|
|
33
|
+
updatedInput
|
|
34
|
+
}
|
|
49
35
|
};
|
|
50
|
-
|
|
51
36
|
process.stdout.write(JSON.stringify(output));
|
|
52
37
|
}
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
try {
|
|
39
|
+
withTelemetrySync("mindlore-model-router", main);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
hookLog("model-router", "error", err?.message ?? String(err));
|
|
42
|
+
}
|
|
@@ -1,69 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* mindlore-post-compact — PostCompact hook
|
|
6
|
-
*
|
|
7
|
-
* After context compaction, re-inject session context:
|
|
8
|
-
* 1. Read INDEX.md
|
|
9
|
-
* 2. Read latest delta
|
|
10
|
-
* 3. Inject via stdout (same as session-focus)
|
|
11
|
-
*
|
|
12
|
-
* This ensures the agent has knowledge context after compaction.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
const { findMindloreDir, getLatestDelta, readConfig, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
2
|
+
"use strict";
|
|
18
3
|
|
|
4
|
+
// hooks/src/mindlore-post-compact.cjs
|
|
5
|
+
var fs = require("fs");
|
|
6
|
+
var path = require("path");
|
|
7
|
+
var { findMindloreDir, getLatestDelta, readConfig, hookLog, withTelemetry } = require("./lib/mindlore-common.cjs");
|
|
19
8
|
function main() {
|
|
20
9
|
const baseDir = findMindloreDir();
|
|
21
10
|
if (!baseDir) return;
|
|
22
|
-
|
|
23
11
|
const output = [];
|
|
24
|
-
|
|
25
|
-
// Re-inject INDEX.md
|
|
26
|
-
const indexPath = path.join(baseDir, 'INDEX.md');
|
|
12
|
+
const indexPath = path.join(baseDir, "INDEX.md");
|
|
27
13
|
if (fs.existsSync(indexPath)) {
|
|
28
|
-
const content = fs.readFileSync(indexPath,
|
|
29
|
-
output.push(`[Mindlore INDEX (post-compact)]
|
|
14
|
+
const content = fs.readFileSync(indexPath, "utf8").trim();
|
|
15
|
+
output.push(`[Mindlore INDEX (post-compact)]
|
|
16
|
+
${content}`);
|
|
30
17
|
}
|
|
31
|
-
|
|
32
|
-
const diaryDir = path.join(baseDir, 'diary');
|
|
33
|
-
|
|
18
|
+
const diaryDir = path.join(baseDir, "diary");
|
|
34
19
|
const latestDelta = getLatestDelta(diaryDir);
|
|
35
20
|
if (latestDelta) {
|
|
36
|
-
const deltaContent = fs.readFileSync(latestDelta,
|
|
21
|
+
const deltaContent = fs.readFileSync(latestDelta, "utf8").trim();
|
|
37
22
|
const deltaName = path.basename(latestDelta);
|
|
38
|
-
output.push(`[Mindlore Delta (post-compact): ${deltaName}]
|
|
23
|
+
output.push(`[Mindlore Delta (post-compact): ${deltaName}]
|
|
24
|
+
${deltaContent}`);
|
|
39
25
|
}
|
|
40
|
-
|
|
41
26
|
try {
|
|
42
|
-
const snapshots = fs.readdirSync(diaryDir)
|
|
43
|
-
.filter(f => f.startsWith('compaction-snapshot-'))
|
|
44
|
-
.sort();
|
|
27
|
+
const snapshots = fs.readdirSync(diaryDir).filter((f) => f.startsWith("compaction-snapshot-")).sort();
|
|
45
28
|
if (snapshots.length > 0) {
|
|
46
29
|
const latestSnapshot = snapshots[snapshots.length - 1];
|
|
47
30
|
const snapshotContent = fs.readFileSync(
|
|
48
|
-
path.join(diaryDir, latestSnapshot),
|
|
31
|
+
path.join(diaryDir, latestSnapshot),
|
|
32
|
+
"utf8"
|
|
49
33
|
).trim();
|
|
50
|
-
output.push(`[Mindlore Compaction Resume]
|
|
34
|
+
output.push(`[Mindlore Compaction Resume]
|
|
35
|
+
${snapshotContent}`);
|
|
51
36
|
}
|
|
52
|
-
} catch (_err) {
|
|
53
|
-
|
|
37
|
+
} catch (_err) {
|
|
38
|
+
}
|
|
54
39
|
if (output.length > 0) {
|
|
55
40
|
const config = readConfig(baseDir);
|
|
56
41
|
const budgetConfig = config?.tokenBudget ?? {};
|
|
57
|
-
const maxInjectChars = (budgetConfig.sessionInject ||
|
|
58
|
-
let joined = output.join(
|
|
42
|
+
const maxInjectChars = (budgetConfig.sessionInject || 2e3) * 4;
|
|
43
|
+
let joined = output.join("\n\n");
|
|
59
44
|
if (joined.length > maxInjectChars) {
|
|
60
|
-
joined = joined.slice(0, maxInjectChars) +
|
|
45
|
+
joined = joined.slice(0, maxInjectChars) + "\n[...truncated by token budget]";
|
|
61
46
|
}
|
|
62
|
-
process.stdout.write(joined +
|
|
47
|
+
process.stdout.write(joined + "\n");
|
|
63
48
|
}
|
|
64
49
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
hookLog('mindlore-post-compact', 'error', err?.message ?? String(err));
|
|
50
|
+
withTelemetry("mindlore-post-compact", main).catch((err) => {
|
|
51
|
+
hookLog("mindlore-post-compact", "error", err?.message ?? String(err));
|
|
68
52
|
process.exit(0);
|
|
69
53
|
});
|