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
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Mindlore lifecycle hooks — session context injection, FTS5 search, decision detection, file sync, compaction handling, read/write guards, model routing",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-session-focus.cjs\""
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-search.cjs\""
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"matcher": "",
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-decision-detector.cjs\""
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"FileChanged": [
|
|
36
|
+
{
|
|
37
|
+
"matcher": "",
|
|
38
|
+
"hooks": [
|
|
39
|
+
{
|
|
40
|
+
"type": "command",
|
|
41
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-index.cjs\""
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"matcher": "",
|
|
47
|
+
"hooks": [
|
|
48
|
+
{
|
|
49
|
+
"type": "command",
|
|
50
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-fts5-sync.cjs\""
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"SessionEnd": [
|
|
56
|
+
{
|
|
57
|
+
"matcher": "",
|
|
58
|
+
"hooks": [
|
|
59
|
+
{
|
|
60
|
+
"type": "command",
|
|
61
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-session-end.cjs\""
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"PreCompact": [
|
|
67
|
+
{
|
|
68
|
+
"matcher": "",
|
|
69
|
+
"hooks": [
|
|
70
|
+
{
|
|
71
|
+
"type": "command",
|
|
72
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-pre-compact.cjs\""
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"PostCompact": [
|
|
78
|
+
{
|
|
79
|
+
"matcher": "",
|
|
80
|
+
"hooks": [
|
|
81
|
+
{
|
|
82
|
+
"type": "command",
|
|
83
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-post-compact.cjs\""
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"PreToolUse": [
|
|
89
|
+
{
|
|
90
|
+
"matcher": "Read",
|
|
91
|
+
"hooks": [
|
|
92
|
+
{
|
|
93
|
+
"type": "command",
|
|
94
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-read-guard.cjs\""
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"matcher": "Write|Edit",
|
|
100
|
+
"hooks": [
|
|
101
|
+
{
|
|
102
|
+
"type": "command",
|
|
103
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-dont-repeat.cjs\""
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"matcher": "Agent",
|
|
109
|
+
"hooks": [
|
|
110
|
+
{
|
|
111
|
+
"type": "command",
|
|
112
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-model-router.cjs\""
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"matcher": "Agent",
|
|
118
|
+
"hooks": [
|
|
119
|
+
{
|
|
120
|
+
"type": "command",
|
|
121
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-research-guard.cjs\""
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"PostToolUse": [
|
|
127
|
+
{
|
|
128
|
+
"matcher": "Read",
|
|
129
|
+
"hooks": [
|
|
130
|
+
{
|
|
131
|
+
"type": "command",
|
|
132
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-post-read.cjs\""
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"CwdChanged": [
|
|
138
|
+
{
|
|
139
|
+
"matcher": "",
|
|
140
|
+
"hooks": [
|
|
141
|
+
{
|
|
142
|
+
"type": "command",
|
|
143
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/mindlore-cwd-changed.cjs\""
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -10,7 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const crypto = require('crypto');
|
|
11
11
|
const os = require('os');
|
|
12
12
|
const { EPISODE_KINDS, isValidKind, DB_BUSY_TIMEOUT_MS } = require('./constants.cjs');
|
|
13
|
-
const { safeMkdir, safeWriteFile } = require('
|
|
13
|
+
const { safeMkdir, safeWriteFile } = require('./secure-io.cjs');
|
|
14
14
|
|
|
15
15
|
const MINDLORE_DIR = '.mindlore';
|
|
16
16
|
const DB_NAME = 'mindlore.db';
|
|
@@ -644,7 +644,7 @@ function resolveWin32Bin(name) {
|
|
|
644
644
|
if (process.platform === 'win32') {
|
|
645
645
|
try {
|
|
646
646
|
return require('child_process')
|
|
647
|
-
.
|
|
647
|
+
.execFileSync('where', [name], { encoding: 'utf8', timeout: 3000, windowsHide: true })
|
|
648
648
|
.trim().split('\n')[0].trim();
|
|
649
649
|
} catch (_e) { /* fall through */ }
|
|
650
650
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
function safeMkdir(dirPath) {
|
|
6
|
+
fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function safeWriteFile(filePath, data) {
|
|
10
|
+
fs.writeFileSync(filePath, data, { encoding: 'utf8', mode: 0o600 });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function safeWriteJson(filePath, obj) {
|
|
14
|
+
safeWriteFile(filePath, JSON.stringify(obj, null, 2) + '\n');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = { safeMkdir, safeWriteFile, safeWriteJson };
|
|
@@ -1,57 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* mindlore-cwd-changed — CwdChanged hook
|
|
6
|
-
*
|
|
7
|
-
* Fires when user changes working directory.
|
|
8
|
-
* CwdChanged has NO inject to Claude — stdout is swallowed, stderr shown to user.
|
|
9
|
-
*
|
|
10
|
-
* Side effects:
|
|
11
|
-
* 1. Detect scope (global ~/.mindlore/ or none)
|
|
12
|
-
* 2. Write scope state to .mindlore/diary/_scope.json for session-focus to read
|
|
13
|
-
* 3. Show user-facing message via stderr
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
const { findMindloreDir, globalDir, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
2
|
+
"use strict";
|
|
19
3
|
|
|
4
|
+
// hooks/src/mindlore-cwd-changed.cjs
|
|
5
|
+
var fs = require("fs");
|
|
6
|
+
var path = require("path");
|
|
7
|
+
var { findMindloreDir, globalDir, hookLog, withTelemetry } = require("./lib/mindlore-common.cjs");
|
|
20
8
|
function main() {
|
|
21
9
|
const cwd = process.cwd();
|
|
22
10
|
const activeDir = findMindloreDir();
|
|
23
|
-
const scope = !activeDir ?
|
|
24
|
-
|
|
11
|
+
const scope = !activeDir ? "none" : activeDir.startsWith(globalDir()) ? "global" : "project";
|
|
25
12
|
if (activeDir) {
|
|
26
|
-
const diaryDir = path.join(activeDir,
|
|
13
|
+
const diaryDir = path.join(activeDir, "diary");
|
|
27
14
|
if (!fs.existsSync(diaryDir)) {
|
|
28
15
|
fs.mkdirSync(diaryDir, { recursive: true });
|
|
29
16
|
}
|
|
30
|
-
|
|
31
|
-
// Dirty-check: skip write if scope hasn't changed
|
|
32
|
-
const scopePath = path.join(diaryDir, '_scope.json');
|
|
17
|
+
const scopePath = path.join(diaryDir, "_scope.json");
|
|
33
18
|
if (fs.existsSync(scopePath)) {
|
|
34
19
|
try {
|
|
35
|
-
const existing = JSON.parse(fs.readFileSync(scopePath,
|
|
20
|
+
const existing = JSON.parse(fs.readFileSync(scopePath, "utf8"));
|
|
36
21
|
if (existing.cwd === cwd && existing.scope === scope) return;
|
|
37
22
|
} catch (_err) {
|
|
38
|
-
// corrupt file — overwrite
|
|
39
23
|
}
|
|
40
24
|
}
|
|
41
|
-
|
|
42
25
|
fs.writeFileSync(scopePath, JSON.stringify({
|
|
43
26
|
scope,
|
|
44
27
|
dir: activeDir,
|
|
45
28
|
cwd,
|
|
46
|
-
timestamp: new Date().toISOString()
|
|
47
|
-
}, null, 2),
|
|
29
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
30
|
+
}, null, 2), "utf8");
|
|
48
31
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
if (scope === "none") {
|
|
33
|
+
process.stderr.write(`[Mindlore] Bu projede mindlore kurulu degil. npx mindlore init calistirin.
|
|
34
|
+
`);
|
|
52
35
|
} else {
|
|
53
|
-
process.stderr.write(`[Mindlore scope: ${scope}] ${activeDir}
|
|
36
|
+
process.stderr.write(`[Mindlore scope: ${scope}] ${activeDir}
|
|
37
|
+
`);
|
|
54
38
|
}
|
|
55
39
|
}
|
|
56
|
-
|
|
57
|
-
|
|
40
|
+
withTelemetry("mindlore-cwd-changed", main).catch((err) => {
|
|
41
|
+
hookLog("cwd-changed", "error", err?.message ?? String(err));
|
|
42
|
+
});
|
|
@@ -1,29 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// hooks/src/mindlore-decision-detector.cjs
|
|
5
|
+
var { findMindloreDir, readHookStdin, hookLog, withTelemetry } = require("./lib/mindlore-common.cjs");
|
|
6
|
+
var SIGNALS_TR = [
|
|
7
|
+
"karar verdik",
|
|
8
|
+
"karar verildi",
|
|
9
|
+
"kararlastirdik",
|
|
10
|
+
"kararla\u015Ft\u0131rd\u0131k",
|
|
11
|
+
"\u015Funu se\xE7tik",
|
|
12
|
+
"sunu sectik",
|
|
13
|
+
"bunu yapmayal\u0131m",
|
|
14
|
+
"bunu yapmayalim",
|
|
15
|
+
"yerine",
|
|
16
|
+
"tercih ettik",
|
|
17
|
+
"onaylandi",
|
|
18
|
+
"onayland\u0131",
|
|
19
|
+
"kesinle\u015Fti",
|
|
20
|
+
"kesinlesti",
|
|
21
|
+
"vazge\xE7tik",
|
|
22
|
+
"vazgectik",
|
|
23
|
+
"iptal ettik"
|
|
19
24
|
];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
+
var SIGNALS_EN = [
|
|
26
|
+
"decided",
|
|
27
|
+
"decision made",
|
|
28
|
+
"let's go with",
|
|
29
|
+
"lets go with",
|
|
30
|
+
"we'll use",
|
|
31
|
+
"well use",
|
|
32
|
+
"approved",
|
|
33
|
+
"settled on",
|
|
34
|
+
"going with",
|
|
35
|
+
"chosen",
|
|
36
|
+
"finalized",
|
|
37
|
+
"rejected"
|
|
25
38
|
];
|
|
26
|
-
|
|
27
39
|
function detectDecision(text) {
|
|
28
40
|
const lower = text.toLowerCase();
|
|
29
41
|
for (const signal of SIGNALS_TR) {
|
|
@@ -34,21 +46,18 @@ function detectDecision(text) {
|
|
|
34
46
|
}
|
|
35
47
|
return null;
|
|
36
48
|
}
|
|
37
|
-
|
|
38
49
|
function main() {
|
|
39
50
|
const baseDir = findMindloreDir();
|
|
40
51
|
if (!baseDir) return;
|
|
41
|
-
|
|
42
|
-
const userText = readHookStdin(['prompt', 'content', 'message']);
|
|
52
|
+
const userText = readHookStdin(["prompt", "content", "message"]);
|
|
43
53
|
if (!userText || userText.length < 10) return;
|
|
44
|
-
|
|
45
54
|
const signal = detectDecision(userText);
|
|
46
55
|
if (signal) {
|
|
47
|
-
process.stdout.write(`[Mindlore: Karar sinyali tespit edildi ("${signal}")
|
|
56
|
+
process.stdout.write(`[Mindlore: Karar sinyali tespit edildi ("${signal}") \u2014 /mindlore-decide record ile kaydetmek ister misin?]
|
|
57
|
+
`);
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
hookLog('mindlore-decision-detector', 'error', err?.message ?? String(err));
|
|
60
|
+
withTelemetry("mindlore-decision-detector", main).catch((err) => {
|
|
61
|
+
hookLog("mindlore-decision-detector", "error", err?.message ?? String(err));
|
|
53
62
|
process.exit(0);
|
|
54
63
|
});
|
|
@@ -1,58 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Sources checked (in order):
|
|
11
|
-
* 1. ~/.claude/lessons/global.md (global rules)
|
|
12
|
-
* 2. ./LESSONS.md (project-level rules, if exists)
|
|
13
|
-
* 3. .mindlore/learnings/*.md (Mindlore learnings, if exists)
|
|
14
|
-
*
|
|
15
|
-
* Advisory only (exit 0) — does not block, injects additionalContext warning.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
const { findMindloreDir, getProjectName, hookLog, withTelemetrySync } = require('./lib/mindlore-common.cjs');
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* File-persisted pattern cache — survives across process invocations.
|
|
25
|
-
* Cache file: .mindlore/diary/_pattern-cache.json
|
|
26
|
-
* Each entry keyed by source file path, stores mtimeMs + extracted patterns.
|
|
27
|
-
* On hit: stat only, no readFile+parse. On miss: read, parse, update cache.
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
let cacheDirty = false;
|
|
31
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// hooks/src/mindlore-dont-repeat.cjs
|
|
5
|
+
var fs = require("fs");
|
|
6
|
+
var path = require("path");
|
|
7
|
+
var os = require("os");
|
|
8
|
+
var { findMindloreDir, getProjectName, hookLog, withTelemetrySync } = require("./lib/mindlore-common.cjs");
|
|
9
|
+
var cacheDirty = false;
|
|
32
10
|
function readCache(cachePath) {
|
|
33
11
|
if (!cachePath) return {};
|
|
34
12
|
try {
|
|
35
|
-
return JSON.parse(fs.readFileSync(cachePath,
|
|
13
|
+
return JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
36
14
|
} catch (_err) {
|
|
37
15
|
return {};
|
|
38
16
|
}
|
|
39
17
|
}
|
|
40
|
-
|
|
41
18
|
function writeCache(cachePath, cache) {
|
|
42
19
|
if (!cachePath || !cacheDirty) return;
|
|
43
20
|
try {
|
|
44
|
-
fs.writeFileSync(cachePath, JSON.stringify(cache),
|
|
45
|
-
} catch (_err) {
|
|
21
|
+
fs.writeFileSync(cachePath, JSON.stringify(cache), "utf8");
|
|
22
|
+
} catch (_err) {
|
|
23
|
+
}
|
|
46
24
|
}
|
|
47
|
-
|
|
48
25
|
function loadPatterns(filePath, cache) {
|
|
49
26
|
try {
|
|
50
27
|
const stat = fs.statSync(filePath);
|
|
51
28
|
const mtimeMs = stat.mtimeMs;
|
|
52
29
|
const cached = cache[filePath];
|
|
53
30
|
if (cached && cached.mtimeMs === mtimeMs) return cached.patterns;
|
|
54
|
-
|
|
55
|
-
const patterns = extractNegativePatterns(fs.readFileSync(filePath, 'utf8'));
|
|
31
|
+
const patterns = extractNegativePatterns(fs.readFileSync(filePath, "utf8"));
|
|
56
32
|
cache[filePath] = { mtimeMs, patterns };
|
|
57
33
|
cacheDirty = true;
|
|
58
34
|
return patterns;
|
|
@@ -60,42 +36,30 @@ function loadPatterns(filePath, cache) {
|
|
|
60
36
|
return [];
|
|
61
37
|
}
|
|
62
38
|
}
|
|
63
|
-
|
|
64
39
|
function extractNegativePatterns(content) {
|
|
65
40
|
const patterns = [];
|
|
66
|
-
const lines = content.split(
|
|
67
|
-
|
|
41
|
+
const lines = content.split("\n");
|
|
68
42
|
for (const line of lines) {
|
|
69
43
|
const trimmed = line.trim();
|
|
70
|
-
// Multi-language: TR (YAPMA, KRITIK) + EN (DON'T, NEVER, AVOID, DO NOT)
|
|
71
44
|
const isNegativeRule = /^-\s*(YAPMA|KRITIK|DON'?T|NEVER|AVOID|DO NOT):/i.test(trimmed);
|
|
72
45
|
if (!isNegativeRule) continue;
|
|
73
|
-
|
|
74
|
-
// Extract backtick-quoted code patterns: `pattern`
|
|
75
46
|
const backtickMatches = trimmed.match(/`([^`]+)`/g);
|
|
76
47
|
if (backtickMatches) {
|
|
77
48
|
for (const match of backtickMatches) {
|
|
78
49
|
const pattern = match.slice(1, -1).trim();
|
|
79
|
-
// Skip short/generic patterns — too many false positives
|
|
80
50
|
if (pattern.length < 8) continue;
|
|
81
51
|
if (/^[^a-zA-Z0-9]+$/.test(pattern)) continue;
|
|
82
|
-
// Skip single words (too generic: "node", "bash", "any")
|
|
83
52
|
if (/^\w+$/.test(pattern) && pattern.length < 12) continue;
|
|
84
|
-
// Skip file extensions and paths
|
|
85
53
|
if (/^\.\w{1,5}$/.test(pattern)) continue;
|
|
86
|
-
if (pattern.startsWith(
|
|
87
|
-
if (pattern.includes(
|
|
88
|
-
// Skip common false-positive patterns
|
|
54
|
+
if (pattern.startsWith("/") || pattern.startsWith("~")) continue;
|
|
55
|
+
if (pattern.includes(".md") || pattern.includes(".json")) continue;
|
|
89
56
|
if (/^(node|bash|npm|git|process|require|import|export|const|let|var)$/i.test(pattern)) continue;
|
|
90
|
-
|
|
91
57
|
patterns.push({
|
|
92
58
|
pattern,
|
|
93
|
-
rule: trimmed.substring(0, 120)
|
|
59
|
+
rule: trimmed.substring(0, 120)
|
|
94
60
|
});
|
|
95
61
|
}
|
|
96
62
|
}
|
|
97
|
-
|
|
98
|
-
// Extract "quoted strings" as patterns
|
|
99
63
|
const quoteMatches = trimmed.match(/"([^"]+)"/g);
|
|
100
64
|
if (quoteMatches) {
|
|
101
65
|
for (const match of quoteMatches) {
|
|
@@ -103,120 +67,98 @@ function extractNegativePatterns(content) {
|
|
|
103
67
|
if (quoted.length < 4) continue;
|
|
104
68
|
patterns.push({
|
|
105
69
|
pattern: quoted,
|
|
106
|
-
rule: trimmed.substring(0, 120)
|
|
70
|
+
rule: trimmed.substring(0, 120)
|
|
107
71
|
});
|
|
108
72
|
}
|
|
109
73
|
}
|
|
110
74
|
}
|
|
111
|
-
|
|
112
75
|
return patterns;
|
|
113
76
|
}
|
|
114
|
-
|
|
115
77
|
function checkContent(content, patterns) {
|
|
116
78
|
const matches = [];
|
|
117
79
|
for (const p of patterns) {
|
|
118
80
|
try {
|
|
119
|
-
const escaped = p.pattern.replace(/[.*+?^${}()|[\]\\]/g,
|
|
120
|
-
const regex = new RegExp(escaped,
|
|
81
|
+
const escaped = p.pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
82
|
+
const regex = new RegExp(escaped, "i");
|
|
121
83
|
if (regex.test(content)) {
|
|
122
84
|
matches.push(p);
|
|
123
85
|
}
|
|
124
|
-
} catch {
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
125
88
|
}
|
|
126
89
|
return matches;
|
|
127
90
|
}
|
|
128
|
-
|
|
129
91
|
function main() {
|
|
130
|
-
let input =
|
|
131
|
-
const stdinTimeout = setTimeout(() => process.exit(0),
|
|
132
|
-
process.stdin.setEncoding(
|
|
133
|
-
process.stdin.on(
|
|
134
|
-
process.stdin.on(
|
|
135
|
-
process.stdin.on(
|
|
92
|
+
let input = "";
|
|
93
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3e3);
|
|
94
|
+
process.stdin.setEncoding("utf8");
|
|
95
|
+
process.stdin.on("error", () => process.exit(0));
|
|
96
|
+
process.stdin.on("data", (chunk) => input += chunk);
|
|
97
|
+
process.stdin.on("end", () => {
|
|
136
98
|
clearTimeout(stdinTimeout);
|
|
137
99
|
try {
|
|
138
|
-
const data = JSON.parse(input ||
|
|
139
|
-
const toolName = data.tool_name ||
|
|
140
|
-
|
|
141
|
-
if (!['Write', 'Edit'].includes(toolName)) {
|
|
100
|
+
const data = JSON.parse(input || "{}");
|
|
101
|
+
const toolName = data.tool_name || "";
|
|
102
|
+
if (!["Write", "Edit"].includes(toolName)) {
|
|
142
103
|
return process.exit(0);
|
|
143
104
|
}
|
|
144
|
-
|
|
145
105
|
const toolInput = data.tool_input || {};
|
|
146
|
-
const filePath = toolInput.file_path ||
|
|
147
|
-
|
|
148
|
-
// Skip non-code files
|
|
106
|
+
const filePath = toolInput.file_path || "";
|
|
149
107
|
if (!filePath) return process.exit(0);
|
|
150
108
|
const ext = path.extname(filePath).toLowerCase();
|
|
151
|
-
const codeExts = [
|
|
109
|
+
const codeExts = [".ts", ".tsx", ".js", ".jsx", ".cjs", ".mjs", ".py", ".go", ".rs", ".java", ".c", ".cpp", ".h", ".sh", ".yaml", ".yml"];
|
|
152
110
|
if (!codeExts.includes(ext)) return process.exit(0);
|
|
153
|
-
|
|
154
|
-
// Skip rule files themselves
|
|
155
111
|
const basename = path.basename(filePath);
|
|
156
|
-
if (basename ===
|
|
112
|
+
if (basename === "LESSONS.md" || basename === "global.md" || basename === "CLAUDE.md") {
|
|
157
113
|
return process.exit(0);
|
|
158
114
|
}
|
|
159
|
-
|
|
160
|
-
// Collect content being written (skip old_string — that's code being removed, not added)
|
|
161
115
|
const allContent = [
|
|
162
|
-
toolInput.content ||
|
|
163
|
-
toolInput.new_string ||
|
|
164
|
-
].join(
|
|
165
|
-
|
|
116
|
+
toolInput.content || "",
|
|
117
|
+
toolInput.new_string || ""
|
|
118
|
+
].join("\n");
|
|
166
119
|
if (allContent.trim().length < 10) return process.exit(0);
|
|
167
|
-
|
|
168
|
-
// Load patterns from all sources (file-persisted mtime cache)
|
|
169
120
|
const mindloreDir = findMindloreDir();
|
|
170
|
-
const cachePath = mindloreDir ? path.join(mindloreDir,
|
|
121
|
+
const cachePath = mindloreDir ? path.join(mindloreDir, "diary", `_pattern-cache-${getProjectName()}.json`) : null;
|
|
171
122
|
const cache = readCache(cachePath);
|
|
172
123
|
const allPatterns = [];
|
|
173
124
|
const cwd = process.cwd();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
allPatterns.push(...loadPatterns(path.join(os.homedir(), '.claude', 'lessons', 'global.md'), cache));
|
|
177
|
-
|
|
178
|
-
// 2. Project LESSONS.md
|
|
179
|
-
allPatterns.push(...loadPatterns(path.join(cwd, 'LESSONS.md'), cache));
|
|
180
|
-
|
|
181
|
-
// 3. Mindlore learnings/ directory
|
|
125
|
+
allPatterns.push(...loadPatterns(path.join(os.homedir(), ".claude", "lessons", "global.md"), cache));
|
|
126
|
+
allPatterns.push(...loadPatterns(path.join(cwd, "LESSONS.md"), cache));
|
|
182
127
|
if (mindloreDir) {
|
|
183
|
-
const learningsDir = path.join(mindloreDir,
|
|
128
|
+
const learningsDir = path.join(mindloreDir, "learnings");
|
|
184
129
|
try {
|
|
185
|
-
const files = fs.readdirSync(learningsDir).filter(f => f.endsWith(
|
|
130
|
+
const files = fs.readdirSync(learningsDir).filter((f) => f.endsWith(".md"));
|
|
186
131
|
for (const file of files) {
|
|
187
132
|
allPatterns.push(...loadPatterns(path.join(learningsDir, file), cache));
|
|
188
133
|
}
|
|
189
|
-
} catch (_err) {
|
|
134
|
+
} catch (_err) {
|
|
135
|
+
}
|
|
190
136
|
}
|
|
191
|
-
|
|
192
137
|
writeCache(cachePath, cache);
|
|
193
|
-
|
|
194
138
|
if (allPatterns.length === 0) return process.exit(0);
|
|
195
|
-
|
|
196
|
-
// Check content against patterns
|
|
197
139
|
const matches = checkContent(allContent, allPatterns);
|
|
198
140
|
if (matches.length === 0) return process.exit(0);
|
|
199
|
-
|
|
200
|
-
// Build warning — max 3 matches shown
|
|
201
141
|
const shown = matches.slice(0, 3);
|
|
202
|
-
const warning = shown.map(
|
|
203
|
-
` - Pattern: \`${m.pattern}\`
|
|
204
|
-
).join(
|
|
205
|
-
const extra = matches.length > 3 ?
|
|
206
|
-
|
|
207
|
-
const msg = `[Mindlore: ${matches.length} dont-repeat rule violation detected]
|
|
208
|
-
|
|
142
|
+
const warning = shown.map(
|
|
143
|
+
(m) => ` - Pattern: \`${m.pattern}\` \u2192 ${m.rule}`
|
|
144
|
+
).join("\n");
|
|
145
|
+
const extra = matches.length > 3 ? `
|
|
146
|
+
... and ${matches.length - 3} more` : "";
|
|
147
|
+
const msg = `[Mindlore: ${matches.length} dont-repeat rule violation detected]
|
|
148
|
+
${warning}${extra}`;
|
|
209
149
|
process.stdout.write(JSON.stringify({
|
|
210
150
|
hookSpecificOutput: {
|
|
211
|
-
hookEventName:
|
|
151
|
+
hookEventName: "PreToolUse",
|
|
212
152
|
additionalContext: msg
|
|
213
153
|
}
|
|
214
154
|
}));
|
|
215
155
|
} catch {
|
|
216
|
-
// Silent fail
|
|
217
156
|
}
|
|
218
157
|
process.exit(0);
|
|
219
158
|
});
|
|
220
159
|
}
|
|
221
|
-
|
|
222
|
-
|
|
160
|
+
try {
|
|
161
|
+
withTelemetrySync("mindlore-dont-repeat", main);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
hookLog("dont-repeat", "error", err?.message ?? String(err));
|
|
164
|
+
}
|