mindlore 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -3
- 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 +70 -0
- package/dist/scripts/bundle-hooks.js.map +1 -0
- package/dist/scripts/init.js +0 -3
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/all-migrations.d.ts.map +1 -1
- package/dist/scripts/lib/all-migrations.js +3 -0
- package/dist/scripts/lib/all-migrations.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +7 -2
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +17 -22
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/mcp-tools.d.ts.map +1 -1
- package/dist/scripts/lib/mcp-tools.js +63 -78
- package/dist/scripts/lib/mcp-tools.js.map +1 -1
- package/dist/scripts/lib/migrations-v072.d.ts +3 -0
- package/dist/scripts/lib/migrations-v072.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v072.js +25 -0
- package/dist/scripts/lib/migrations-v072.js.map +1 -0
- package/dist/scripts/lib/relation-helpers.d.ts +15 -0
- package/dist/scripts/lib/relation-helpers.d.ts.map +1 -0
- package/dist/scripts/lib/relation-helpers.js +30 -0
- package/dist/scripts/lib/relation-helpers.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/get-adapter.d.ts +21 -0
- package/dist/scripts/lib/tool-adapters/get-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/get-adapter.js +51 -0
- package/dist/scripts/lib/tool-adapters/get-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/relate-adapter.d.ts +34 -0
- package/dist/scripts/lib/tool-adapters/relate-adapter.d.ts.map +1 -0
- package/dist/scripts/lib/tool-adapters/relate-adapter.js +43 -0
- package/dist/scripts/lib/tool-adapters/relate-adapter.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.d.ts +5 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/search-adapter.js +37 -0
- package/dist/scripts/lib/tool-adapters/search-adapter.js.map +1 -1
- package/dist/scripts/mcp-server.js +1 -1
- package/dist/scripts/mcp-server.js.map +1 -1
- package/dist/tests/dont-repeat-dedup.test.d.ts +2 -0
- package/dist/tests/dont-repeat-dedup.test.d.ts.map +1 -0
- package/dist/tests/dont-repeat-dedup.test.js +93 -0
- package/dist/tests/dont-repeat-dedup.test.js.map +1 -0
- package/dist/tests/e2e-kg-pipeline.test.d.ts +2 -0
- package/dist/tests/e2e-kg-pipeline.test.d.ts.map +1 -0
- package/dist/tests/e2e-kg-pipeline.test.js +59 -0
- package/dist/tests/e2e-kg-pipeline.test.js.map +1 -0
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +2 -1
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/hook-smoke.test.js +1 -1
- package/dist/tests/hook-smoke.test.js.map +1 -1
- package/dist/tests/mcp-get-tool.test.d.ts +2 -0
- package/dist/tests/mcp-get-tool.test.d.ts.map +1 -0
- package/dist/tests/mcp-get-tool.test.js +93 -0
- package/dist/tests/mcp-get-tool.test.js.map +1 -0
- package/dist/tests/mcp-relate-tool.test.d.ts +2 -0
- package/dist/tests/mcp-relate-tool.test.d.ts.map +1 -0
- package/dist/tests/mcp-relate-tool.test.js +85 -0
- package/dist/tests/mcp-relate-tool.test.js.map +1 -0
- package/dist/tests/mcp-server.test.js +3 -1
- package/dist/tests/mcp-server.test.js.map +1 -1
- package/dist/tests/mcp-tools.test.js +20 -0
- package/dist/tests/mcp-tools.test.js.map +1 -1
- package/dist/tests/memory-relate.test.d.ts +2 -0
- package/dist/tests/memory-relate.test.d.ts.map +1 -0
- package/dist/tests/memory-relate.test.js +70 -0
- package/dist/tests/memory-relate.test.js.map +1 -0
- package/dist/tests/migrations-v063.test.js +1 -1
- package/dist/tests/migrations-v072.test.d.ts +2 -0
- package/dist/tests/migrations-v072.test.d.ts.map +1 -0
- package/dist/tests/migrations-v072.test.js +74 -0
- package/dist/tests/migrations-v072.test.js.map +1 -0
- package/dist/tests/plugin-cache-regression.test.d.ts +2 -0
- package/dist/tests/plugin-cache-regression.test.d.ts.map +1 -0
- package/dist/tests/plugin-cache-regression.test.js +19 -0
- package/dist/tests/plugin-cache-regression.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/hooks/cc-memory-bulk-sync.cjs +606 -0
- package/hooks/cc-session-sync.cjs +856 -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 +75 -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 +1156 -93
- package/hooks/mindlore-session-end.cjs +155 -276
- package/hooks/mindlore-session-focus.cjs +672 -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 +243 -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 +5 -4
- package/templates/config.json +1 -1
|
@@ -1,116 +1,1189 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
3
28
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
// dist/scripts/lib/constants.js
|
|
30
|
+
var require_constants = __commonJS({
|
|
31
|
+
"dist/scripts/lib/constants.js"(exports2) {
|
|
32
|
+
"use strict";
|
|
33
|
+
var __importDefault = exports2 && exports2.__importDefault || function(mod) {
|
|
34
|
+
return mod && mod.__esModule ? mod : { "default": mod };
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
37
|
+
exports2.CONSOLIDATION_THRESHOLD = exports2.STALE_THRESHOLD = exports2.DECAY_HALF_LIFE_DAYS = exports2.DEFAULT_TOKEN_BUDGET = exports2.CC_MEMORY_BOOST = exports2.CC_SUBAGENT_CATEGORY = exports2.CC_SESSION_CATEGORY = exports2.CC_MEMORY_CATEGORY = exports2.CC_MEMORY_DIR = exports2.CC_MEMORY_PATH_MARKER = exports2.TYPE_TO_DIR = exports2.RELATED_OVERFETCH = exports2.MAX_RELATED_SOURCES = exports2.RELATION_PRIORITY = exports2.SYMMETRIC_TYPES = exports2.RELATION_TYPES = exports2.QUALITY_HEURISTICS = exports2.QUALITY_VALUES = exports2.FRONTMATTER_TYPES = exports2.FTS5_COLUMNS = exports2.STOP_WORDS = exports2.TURKISH_WORD_RE = exports2.STOP_WORDS_MIN_LENGTH = exports2.SESSION_CATEGORIES = exports2.CATEGORIES = exports2.SCHEMA_VERSION = exports2.DEFAULT_MODELS = exports2.CONFIG_FILE = exports2.MCP_BUSY_TIMEOUT_MS = exports2.DB_BUSY_TIMEOUT_MS = exports2.SKIP_FILES = exports2.DIRECTORIES = exports2.DB_NAME = exports2.GLOBAL_MINDLORE_DIR = exports2.MINDLORE_DIR = exports2.KNOWN_HOOK_EVENTS = void 0;
|
|
38
|
+
exports2.isKnownHookEvent = isKnownHookEvent;
|
|
39
|
+
exports2.isSessionCategory = isSessionCategory;
|
|
40
|
+
exports2.fixVersionTokens = fixVersionTokens;
|
|
41
|
+
exports2.buildPriorityCase = buildPriorityCase;
|
|
42
|
+
exports2.homedir = homedir;
|
|
43
|
+
exports2.getActiveMindloreDir = getActiveMindloreDir;
|
|
44
|
+
exports2.getAllDbs = getAllDbs2;
|
|
45
|
+
exports2.getProjectName = getProjectName;
|
|
46
|
+
exports2.log = log;
|
|
47
|
+
exports2.isContentFile = isContentFile;
|
|
48
|
+
exports2.resolveHookCommon = resolveHookCommon;
|
|
49
|
+
exports2.hasYoutubeTranscript = hasYoutubeTranscript;
|
|
50
|
+
var os_1 = __importDefault(require("os"));
|
|
51
|
+
var fs_1 = __importDefault(require("fs"));
|
|
52
|
+
var path_1 = __importDefault(require("path"));
|
|
53
|
+
exports2.KNOWN_HOOK_EVENTS = [
|
|
54
|
+
"SessionStart",
|
|
55
|
+
"SessionEnd",
|
|
56
|
+
"UserPromptSubmit",
|
|
57
|
+
"FileChanged",
|
|
58
|
+
"PreToolUse",
|
|
59
|
+
"PostToolUse",
|
|
60
|
+
"PreCompact",
|
|
61
|
+
"PostCompact",
|
|
62
|
+
"CwdChanged"
|
|
63
|
+
];
|
|
64
|
+
function isKnownHookEvent(s) {
|
|
65
|
+
return exports2.KNOWN_HOOK_EVENTS.includes(s);
|
|
66
|
+
}
|
|
67
|
+
exports2.MINDLORE_DIR = ".mindlore";
|
|
68
|
+
exports2.GLOBAL_MINDLORE_DIR = process.env.MINDLORE_HOME ?? path_1.default.join(os_1.default.homedir(), exports2.MINDLORE_DIR);
|
|
69
|
+
exports2.DB_NAME = "mindlore.db";
|
|
70
|
+
exports2.DIRECTORIES = [
|
|
71
|
+
"raw",
|
|
72
|
+
"sources",
|
|
73
|
+
"domains",
|
|
74
|
+
"analyses",
|
|
75
|
+
"insights",
|
|
76
|
+
"connections",
|
|
77
|
+
"learnings",
|
|
78
|
+
"diary",
|
|
79
|
+
"decisions",
|
|
80
|
+
"logs",
|
|
81
|
+
"memory"
|
|
82
|
+
];
|
|
83
|
+
exports2.SKIP_FILES = /* @__PURE__ */ new Set(["INDEX.md", "SCHEMA.md", "log.md"]);
|
|
84
|
+
exports2.DB_BUSY_TIMEOUT_MS = 2e3;
|
|
85
|
+
exports2.MCP_BUSY_TIMEOUT_MS = 5e3;
|
|
86
|
+
exports2.CONFIG_FILE = "config.json";
|
|
87
|
+
exports2.DEFAULT_MODELS = {
|
|
88
|
+
ingest: "haiku",
|
|
89
|
+
evolve: "sonnet",
|
|
90
|
+
explore: "sonnet",
|
|
91
|
+
default: "haiku"
|
|
92
|
+
};
|
|
93
|
+
exports2.SCHEMA_VERSION = 1;
|
|
94
|
+
exports2.CATEGORIES = ["sources", "analyses", "domains", "episodes", "decisions", "raw", "sessions", "cc_memory", "cc-session", "cc-subagent", "diary", "insights", "connections", "learnings", "memory"];
|
|
95
|
+
exports2.SESSION_CATEGORIES = ["cc-subagent", "cc-session"];
|
|
96
|
+
function isSessionCategory(category) {
|
|
97
|
+
return exports2.SESSION_CATEGORIES.includes(category);
|
|
98
|
+
}
|
|
99
|
+
exports2.STOP_WORDS_MIN_LENGTH = 2;
|
|
100
|
+
exports2.TURKISH_WORD_RE = /[^\w\sçğıöşüÇĞİÖŞÜ-]/g;
|
|
101
|
+
exports2.STOP_WORDS = /* @__PURE__ */ new Set([
|
|
102
|
+
// English
|
|
103
|
+
"the",
|
|
104
|
+
"a",
|
|
105
|
+
"an",
|
|
106
|
+
"is",
|
|
107
|
+
"are",
|
|
108
|
+
"was",
|
|
109
|
+
"were",
|
|
110
|
+
"be",
|
|
111
|
+
"been",
|
|
112
|
+
"being",
|
|
113
|
+
"have",
|
|
114
|
+
"has",
|
|
115
|
+
"had",
|
|
116
|
+
"do",
|
|
117
|
+
"does",
|
|
118
|
+
"did",
|
|
119
|
+
"will",
|
|
120
|
+
"would",
|
|
121
|
+
"could",
|
|
122
|
+
"should",
|
|
123
|
+
"may",
|
|
124
|
+
"might",
|
|
125
|
+
"can",
|
|
126
|
+
"shall",
|
|
127
|
+
"to",
|
|
128
|
+
"of",
|
|
129
|
+
"in",
|
|
130
|
+
"for",
|
|
131
|
+
"on",
|
|
132
|
+
"with",
|
|
133
|
+
"at",
|
|
134
|
+
"by",
|
|
135
|
+
"from",
|
|
136
|
+
"as",
|
|
137
|
+
"into",
|
|
138
|
+
"through",
|
|
139
|
+
"during",
|
|
140
|
+
"it",
|
|
141
|
+
"its",
|
|
142
|
+
"this",
|
|
143
|
+
"that",
|
|
144
|
+
"these",
|
|
145
|
+
"those",
|
|
146
|
+
"what",
|
|
147
|
+
"which",
|
|
148
|
+
"who",
|
|
149
|
+
"whom",
|
|
150
|
+
"how",
|
|
151
|
+
"when",
|
|
152
|
+
"where",
|
|
153
|
+
"why",
|
|
154
|
+
"not",
|
|
155
|
+
"no",
|
|
156
|
+
"nor",
|
|
157
|
+
"so",
|
|
158
|
+
"if",
|
|
159
|
+
"or",
|
|
160
|
+
"but",
|
|
161
|
+
"all",
|
|
162
|
+
"each",
|
|
163
|
+
"every",
|
|
164
|
+
"both",
|
|
165
|
+
"few",
|
|
166
|
+
"more",
|
|
167
|
+
"most",
|
|
168
|
+
"other",
|
|
169
|
+
"some",
|
|
170
|
+
"such",
|
|
171
|
+
"only",
|
|
172
|
+
"own",
|
|
173
|
+
"same",
|
|
174
|
+
"than",
|
|
175
|
+
"and",
|
|
176
|
+
"about",
|
|
177
|
+
"between",
|
|
178
|
+
"after",
|
|
179
|
+
"before",
|
|
180
|
+
"above",
|
|
181
|
+
"below",
|
|
182
|
+
"up",
|
|
183
|
+
"down",
|
|
184
|
+
"out",
|
|
185
|
+
"very",
|
|
186
|
+
"just",
|
|
187
|
+
"also",
|
|
188
|
+
"now",
|
|
189
|
+
"then",
|
|
190
|
+
"here",
|
|
191
|
+
"there",
|
|
192
|
+
"too",
|
|
193
|
+
"yet",
|
|
194
|
+
"my",
|
|
195
|
+
"your",
|
|
196
|
+
"his",
|
|
197
|
+
"her",
|
|
198
|
+
"our",
|
|
199
|
+
"their",
|
|
200
|
+
"me",
|
|
201
|
+
"him",
|
|
202
|
+
"us",
|
|
203
|
+
"them",
|
|
204
|
+
"i",
|
|
205
|
+
"you",
|
|
206
|
+
"he",
|
|
207
|
+
"she",
|
|
208
|
+
"we",
|
|
209
|
+
"they",
|
|
210
|
+
// Turkish
|
|
211
|
+
"bir",
|
|
212
|
+
"bu",
|
|
213
|
+
"su",
|
|
214
|
+
"ne",
|
|
215
|
+
"nas\u0131l",
|
|
216
|
+
"neden",
|
|
217
|
+
"var",
|
|
218
|
+
"yok",
|
|
219
|
+
"mi",
|
|
220
|
+
"mu",
|
|
221
|
+
"m\u0131",
|
|
222
|
+
"ile",
|
|
223
|
+
"i\xE7in",
|
|
224
|
+
"de",
|
|
225
|
+
"da",
|
|
226
|
+
"ve",
|
|
227
|
+
"veya",
|
|
228
|
+
"ama",
|
|
229
|
+
"ise",
|
|
230
|
+
"hem",
|
|
231
|
+
"bakal\u0131m",
|
|
232
|
+
"gel",
|
|
233
|
+
"git",
|
|
234
|
+
"yap",
|
|
235
|
+
"et",
|
|
236
|
+
"al",
|
|
237
|
+
"ver",
|
|
238
|
+
"evet",
|
|
239
|
+
"hay\u0131r",
|
|
240
|
+
"tamam",
|
|
241
|
+
"ok",
|
|
242
|
+
"oldu",
|
|
243
|
+
"olur",
|
|
244
|
+
"dur",
|
|
245
|
+
"\u015Fimdi",
|
|
246
|
+
"sonra",
|
|
247
|
+
"\xF6nce",
|
|
248
|
+
"hemen",
|
|
249
|
+
"biraz",
|
|
250
|
+
"lan",
|
|
251
|
+
"ya",
|
|
252
|
+
"ki",
|
|
253
|
+
"abi",
|
|
254
|
+
"hadi",
|
|
255
|
+
"hey",
|
|
256
|
+
"selam",
|
|
257
|
+
"olarak",
|
|
258
|
+
"olan",
|
|
259
|
+
"gibi",
|
|
260
|
+
"kadar",
|
|
261
|
+
"daha",
|
|
262
|
+
"\xE7ok",
|
|
263
|
+
"en",
|
|
264
|
+
"bunu",
|
|
265
|
+
"buna",
|
|
266
|
+
"i\xE7inde",
|
|
267
|
+
"\xFCzerinde",
|
|
268
|
+
"aras\u0131nda",
|
|
269
|
+
"sonucu",
|
|
270
|
+
"taraf\u0131ndan",
|
|
271
|
+
"zaten",
|
|
272
|
+
"gayet",
|
|
273
|
+
"acaba",
|
|
274
|
+
"nedir",
|
|
275
|
+
"midir",
|
|
276
|
+
"mudur",
|
|
277
|
+
// Generic technical
|
|
278
|
+
"hook",
|
|
279
|
+
"file",
|
|
280
|
+
"dosya",
|
|
281
|
+
"kullan",
|
|
282
|
+
"ekle",
|
|
283
|
+
"yaz",
|
|
284
|
+
"oku",
|
|
285
|
+
"\xE7al\u0131\u015Ft\u0131r",
|
|
286
|
+
"kontrol",
|
|
287
|
+
"test",
|
|
288
|
+
"check",
|
|
289
|
+
"run",
|
|
290
|
+
"add",
|
|
291
|
+
"update",
|
|
292
|
+
"config",
|
|
293
|
+
"setup",
|
|
294
|
+
"install",
|
|
295
|
+
"start",
|
|
296
|
+
"stop",
|
|
297
|
+
"create",
|
|
298
|
+
"delete",
|
|
299
|
+
"remove",
|
|
300
|
+
"set",
|
|
301
|
+
"get",
|
|
302
|
+
"list",
|
|
303
|
+
"show",
|
|
304
|
+
"view",
|
|
305
|
+
"open",
|
|
306
|
+
"close",
|
|
307
|
+
"save",
|
|
308
|
+
"load"
|
|
309
|
+
]);
|
|
310
|
+
var VERSION_RE = /v(\d+)\.(\d+)(?:\.(\d+))?/g;
|
|
311
|
+
function fixVersionTokens(query) {
|
|
312
|
+
return query.replace(VERSION_RE, (_m, a, b, c) => c ? `"v${a} ${b} ${c}"` : `"v${a} ${b}"`);
|
|
313
|
+
}
|
|
314
|
+
exports2.FTS5_COLUMNS = ["path", "slug", "description", "type", "category", "title", "content", "tags", "quality", "date_captured", "project"];
|
|
315
|
+
exports2.FRONTMATTER_TYPES = ["raw", "source", "domain", "analysis", "diary", "decision", "insight", "connection", "learning", "feedback", "user", "project", "reference", "note"];
|
|
316
|
+
exports2.QUALITY_VALUES = ["high", "medium", "low"];
|
|
317
|
+
exports2.QUALITY_HEURISTICS = {
|
|
318
|
+
"github-repo": "high",
|
|
319
|
+
"docs": "high",
|
|
320
|
+
"blog": "medium",
|
|
321
|
+
"video": "medium",
|
|
322
|
+
"x-thread": "medium",
|
|
323
|
+
"text-paste": "low",
|
|
324
|
+
"snippet": "low",
|
|
325
|
+
"forum": "low",
|
|
326
|
+
"cc-session": "low",
|
|
327
|
+
"cc-subagent": "low"
|
|
328
|
+
};
|
|
329
|
+
exports2.RELATION_TYPES = ["cites", "extends", "contradicts", "supersedes"];
|
|
330
|
+
exports2.SYMMETRIC_TYPES = /* @__PURE__ */ new Set(["contradicts"]);
|
|
331
|
+
exports2.RELATION_PRIORITY = {
|
|
332
|
+
supersedes: 1,
|
|
333
|
+
contradicts: 2,
|
|
334
|
+
extends: 3,
|
|
335
|
+
cites: 4
|
|
336
|
+
};
|
|
337
|
+
exports2.MAX_RELATED_SOURCES = 5;
|
|
338
|
+
exports2.RELATED_OVERFETCH = 10;
|
|
339
|
+
function buildPriorityCase() {
|
|
340
|
+
return Object.entries(exports2.RELATION_PRIORITY).map(([type, priority]) => `WHEN '${type}' THEN ${priority}`).join(" ");
|
|
341
|
+
}
|
|
342
|
+
exports2.TYPE_TO_DIR = {
|
|
343
|
+
raw: "raw",
|
|
344
|
+
source: "sources",
|
|
345
|
+
domain: "domains",
|
|
346
|
+
analysis: "analyses",
|
|
347
|
+
insight: "insights",
|
|
348
|
+
connection: "connections",
|
|
349
|
+
learning: "learnings",
|
|
350
|
+
decision: "decisions",
|
|
351
|
+
diary: "diary",
|
|
352
|
+
feedback: "memory",
|
|
353
|
+
user: "memory",
|
|
354
|
+
project: "memory",
|
|
355
|
+
reference: "memory",
|
|
356
|
+
note: "memory"
|
|
357
|
+
};
|
|
358
|
+
exports2.CC_MEMORY_PATH_MARKER = path_1.default.join(".claude", "projects");
|
|
359
|
+
exports2.CC_MEMORY_DIR = "memory";
|
|
360
|
+
exports2.CC_MEMORY_CATEGORY = "cc-memory";
|
|
361
|
+
exports2.CC_SESSION_CATEGORY = "cc-session";
|
|
362
|
+
exports2.CC_SUBAGENT_CATEGORY = "cc-subagent";
|
|
363
|
+
exports2.CC_MEMORY_BOOST = 1.2;
|
|
364
|
+
function homedir() {
|
|
365
|
+
return os_1.default.homedir();
|
|
366
|
+
}
|
|
367
|
+
function getActiveMindloreDir() {
|
|
368
|
+
return exports2.GLOBAL_MINDLORE_DIR;
|
|
369
|
+
}
|
|
370
|
+
function getAllDbs2() {
|
|
371
|
+
const dbPath = path_1.default.join(exports2.GLOBAL_MINDLORE_DIR, exports2.DB_NAME);
|
|
372
|
+
if (fs_1.default.existsSync(dbPath))
|
|
373
|
+
return [dbPath];
|
|
374
|
+
return [];
|
|
375
|
+
}
|
|
376
|
+
function getProjectName() {
|
|
377
|
+
return path_1.default.basename(process.cwd());
|
|
378
|
+
}
|
|
379
|
+
function log(msg) {
|
|
380
|
+
console.log(` ${msg}`);
|
|
381
|
+
}
|
|
382
|
+
function isContentFile(filePath) {
|
|
383
|
+
return !exports2.SKIP_FILES.has(path_1.default.basename(filePath));
|
|
384
|
+
}
|
|
385
|
+
function resolveHookCommon(callerDir) {
|
|
386
|
+
let dir = callerDir;
|
|
387
|
+
for (let i = 0; i < 5; i++) {
|
|
388
|
+
const target = path_1.default.join(dir, "hooks", "lib", "mindlore-common.cjs");
|
|
389
|
+
if (fs_1.default.existsSync(target))
|
|
390
|
+
return target;
|
|
391
|
+
const parent = path_1.default.dirname(dir);
|
|
392
|
+
if (parent === dir)
|
|
393
|
+
break;
|
|
394
|
+
dir = parent;
|
|
395
|
+
}
|
|
396
|
+
return path_1.default.resolve(callerDir, "..", "..", "hooks", "lib", "mindlore-common.cjs");
|
|
397
|
+
}
|
|
398
|
+
function hasYoutubeTranscript() {
|
|
399
|
+
try {
|
|
400
|
+
require.resolve("youtube-transcript");
|
|
401
|
+
return true;
|
|
402
|
+
} catch (_err) {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
exports2.DEFAULT_TOKEN_BUDGET = {
|
|
407
|
+
sessionInject: 2e3,
|
|
408
|
+
searchResults: 1500,
|
|
409
|
+
perResult: 500
|
|
410
|
+
};
|
|
411
|
+
exports2.DECAY_HALF_LIFE_DAYS = 30;
|
|
412
|
+
exports2.STALE_THRESHOLD = 0.3;
|
|
413
|
+
exports2.CONSOLIDATION_THRESHOLD = 50;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
11
416
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
417
|
+
// dist/scripts/lib/db-helpers.js
|
|
418
|
+
var require_db_helpers = __commonJS({
|
|
419
|
+
"dist/scripts/lib/db-helpers.js"(exports2) {
|
|
420
|
+
"use strict";
|
|
421
|
+
var __importDefault = exports2 && exports2.__importDefault || function(mod) {
|
|
422
|
+
return mod && mod.__esModule ? mod : { "default": mod };
|
|
423
|
+
};
|
|
424
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
425
|
+
exports2.dbGet = dbGet;
|
|
426
|
+
exports2.dbAll = dbAll;
|
|
427
|
+
exports2.dbPragma = dbPragma;
|
|
428
|
+
exports2.withReadonlyDb = withReadonlyDb;
|
|
429
|
+
exports2.openDatabaseTs = openDatabaseTs;
|
|
430
|
+
var better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
431
|
+
var fs_1 = __importDefault(require("fs"));
|
|
432
|
+
var constants_js_1 = require_constants();
|
|
433
|
+
function dbGet(db, sql, ...params) {
|
|
434
|
+
const result = db.prepare(sql).get(...params);
|
|
435
|
+
if (result === void 0)
|
|
436
|
+
return void 0;
|
|
437
|
+
if (typeof result !== "object" || result === null) {
|
|
438
|
+
throw new TypeError(`Expected object from query, got ${typeof result}`);
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
function dbAll(db, sql, ...params) {
|
|
443
|
+
const results = db.prepare(sql).all(...params);
|
|
444
|
+
return results;
|
|
445
|
+
}
|
|
446
|
+
function dbPragma(db, pragma) {
|
|
447
|
+
const result = db.pragma(pragma);
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
function withReadonlyDb(dbPath, fn) {
|
|
451
|
+
let db = null;
|
|
452
|
+
try {
|
|
453
|
+
db = new better_sqlite3_1.default(dbPath, { readonly: true });
|
|
454
|
+
return fn(db);
|
|
455
|
+
} catch {
|
|
456
|
+
return void 0;
|
|
457
|
+
} finally {
|
|
458
|
+
db?.close();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function openDatabaseTs(dbPath, options) {
|
|
462
|
+
try {
|
|
463
|
+
if (!fs_1.default.existsSync(dbPath))
|
|
464
|
+
return null;
|
|
465
|
+
const readonly = options?.readonly ?? false;
|
|
466
|
+
const db = new better_sqlite3_1.default(dbPath, { readonly });
|
|
467
|
+
if (!readonly) {
|
|
468
|
+
db.pragma("journal_mode = WAL");
|
|
469
|
+
db.pragma(`busy_timeout = ${constants_js_1.DB_BUSY_TIMEOUT_MS}`);
|
|
470
|
+
}
|
|
471
|
+
return db;
|
|
472
|
+
} catch {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
15
478
|
|
|
16
|
-
|
|
17
|
-
|
|
479
|
+
// dist/scripts/lib/err-msg.js
|
|
480
|
+
var require_err_msg = __commonJS({
|
|
481
|
+
"dist/scripts/lib/err-msg.js"(exports2) {
|
|
482
|
+
"use strict";
|
|
483
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
484
|
+
exports2.errMsg = errMsg;
|
|
485
|
+
function errMsg(err) {
|
|
486
|
+
return err instanceof Error ? err.message : String(err);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
});
|
|
18
490
|
|
|
19
|
-
|
|
491
|
+
// dist/scripts/lib/rrf.js
|
|
492
|
+
var require_rrf = __commonJS({
|
|
493
|
+
"dist/scripts/lib/rrf.js"(exports2) {
|
|
494
|
+
"use strict";
|
|
495
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
496
|
+
exports2.sanitizeFtsQuery = sanitizeFtsQuery;
|
|
497
|
+
exports2.computeRRF = computeRRF;
|
|
498
|
+
exports2.searchPorter = searchPorter;
|
|
499
|
+
exports2.searchTrigram = searchTrigram;
|
|
500
|
+
var db_helpers_js_1 = require_db_helpers();
|
|
501
|
+
var err_msg_js_1 = require_err_msg();
|
|
502
|
+
function sanitizeFtsQuery(query) {
|
|
503
|
+
return query.replace(/["*(){}[\]^~:-]/g, " ").replace(/\s+/g, " ").trim();
|
|
504
|
+
}
|
|
505
|
+
var BM25_RANK_EXPR = "bm25(mindlore_fts, 1, 1, 1, 5.0, 1, 1) as bm";
|
|
506
|
+
function computeRRF(porterResults, trigramResults, options = {}) {
|
|
507
|
+
const k = options.k ?? 60;
|
|
508
|
+
const scores = /* @__PURE__ */ new Map();
|
|
509
|
+
for (const list of [porterResults, trigramResults]) {
|
|
510
|
+
for (const r of list) {
|
|
511
|
+
const existing = scores.get(r.slug);
|
|
512
|
+
const rrfScore = 1 / (k + r.rank);
|
|
513
|
+
if (existing) {
|
|
514
|
+
existing.score += rrfScore;
|
|
515
|
+
} else {
|
|
516
|
+
scores.set(r.slug, { ...r, score: rrfScore });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
let results = Array.from(scores.values()).sort((a, b) => b.score - a.score);
|
|
521
|
+
if (options.dedupByPath) {
|
|
522
|
+
const seen = /* @__PURE__ */ new Set();
|
|
523
|
+
results = results.filter((r) => {
|
|
524
|
+
if (seen.has(r.path))
|
|
525
|
+
return false;
|
|
526
|
+
seen.add(r.path);
|
|
527
|
+
return true;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return results;
|
|
531
|
+
}
|
|
532
|
+
function _searchFts(db, p) {
|
|
533
|
+
const sql = p.project ? `SELECT path, slug, description, title, category, tags, content, ${p.rankExpr} FROM ${p.table} WHERE ${p.table} MATCH ? AND project = ? ORDER BY ${p.orderBy} LIMIT ?` : `SELECT path, slug, description, title, category, tags, content, ${p.rankExpr} FROM ${p.table} WHERE ${p.table} MATCH ? ORDER BY ${p.orderBy} LIMIT ?`;
|
|
534
|
+
const params = p.project ? [p.query, p.project, p.limit] : [p.query, p.limit];
|
|
535
|
+
return (0, db_helpers_js_1.dbAll)(db, sql, ...params).map((r, i) => ({ ...r, rank: i + 1, score: 0 }));
|
|
536
|
+
}
|
|
537
|
+
function searchPorter(db, options) {
|
|
538
|
+
const sanitized = sanitizeFtsQuery(options.query);
|
|
539
|
+
if (!sanitized)
|
|
540
|
+
return [];
|
|
541
|
+
return _searchFts(db, { table: "mindlore_fts", rankExpr: BM25_RANK_EXPR, orderBy: "bm", query: sanitized, project: options.project, limit: options.limit });
|
|
542
|
+
}
|
|
543
|
+
function searchTrigram(db, options) {
|
|
544
|
+
const sanitized = sanitizeFtsQuery(options.query);
|
|
545
|
+
if (!sanitized)
|
|
546
|
+
return [];
|
|
547
|
+
try {
|
|
548
|
+
return _searchFts(db, { table: "mindlore_fts_trigram", rankExpr: "rank", orderBy: "rank", query: sanitized, project: options.project, limit: options.limit });
|
|
549
|
+
} catch (err) {
|
|
550
|
+
const msg = (0, err_msg_js_1.errMsg)(err);
|
|
551
|
+
if (!msg.includes("no such table")) {
|
|
552
|
+
console.warn(`searchTrigram: ${msg}`);
|
|
553
|
+
}
|
|
554
|
+
return [];
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// dist/scripts/lib/fuzzy.js
|
|
561
|
+
var require_fuzzy = __commonJS({
|
|
562
|
+
"dist/scripts/lib/fuzzy.js"(exports2) {
|
|
563
|
+
"use strict";
|
|
564
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
565
|
+
exports2.levenshtein = levenshtein;
|
|
566
|
+
exports2.findClosestWords = findClosestWords;
|
|
567
|
+
exports2.loadVocabulary = loadVocabulary;
|
|
568
|
+
exports2.invalidateVocabCache = invalidateVocabCache;
|
|
569
|
+
exports2.populateVocabulary = populateVocabulary;
|
|
570
|
+
exports2.correctQuery = correctQuery;
|
|
571
|
+
var db_helpers_js_1 = require_db_helpers();
|
|
572
|
+
var constants_js_1 = require_constants();
|
|
573
|
+
function levenshtein(a, b) {
|
|
574
|
+
const m = a.length, n = b.length;
|
|
575
|
+
const prev = new Int32Array(n + 1);
|
|
576
|
+
const curr = new Int32Array(n + 1);
|
|
577
|
+
for (let j = 0; j <= n; j++)
|
|
578
|
+
prev[j] = j;
|
|
579
|
+
for (let i = 1; i <= m; i++) {
|
|
580
|
+
curr[0] = i;
|
|
581
|
+
for (let j = 1; j <= n; j++) {
|
|
582
|
+
curr[j] = a[i - 1] === b[j - 1] ? prev[j - 1] : 1 + Math.min(prev[j], curr[j - 1], prev[j - 1]);
|
|
583
|
+
}
|
|
584
|
+
for (let j = 0; j <= n; j++)
|
|
585
|
+
prev[j] = curr[j];
|
|
586
|
+
}
|
|
587
|
+
return prev[n];
|
|
588
|
+
}
|
|
589
|
+
function maxDistance(wordLen) {
|
|
590
|
+
if (wordLen <= 4)
|
|
591
|
+
return 1;
|
|
592
|
+
if (wordLen <= 7)
|
|
593
|
+
return 2;
|
|
594
|
+
return 3;
|
|
595
|
+
}
|
|
596
|
+
function findClosestWords(word, vocabulary, limit = 3) {
|
|
597
|
+
const maxDist = maxDistance(word.length);
|
|
598
|
+
const lower = word.toLowerCase();
|
|
599
|
+
const candidates = [];
|
|
600
|
+
for (const v of vocabulary) {
|
|
601
|
+
if (Math.abs(v.length - lower.length) > maxDist)
|
|
602
|
+
continue;
|
|
603
|
+
const dist = levenshtein(lower, v.toLowerCase());
|
|
604
|
+
if (dist > 0 && dist <= maxDist) {
|
|
605
|
+
candidates.push({ word: v, dist });
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return candidates.sort((a, b) => a.dist - b.dist).slice(0, limit).map((c) => c.word);
|
|
609
|
+
}
|
|
610
|
+
var vocabCache = null;
|
|
611
|
+
function loadVocabulary(db) {
|
|
612
|
+
const dbName = db.name;
|
|
613
|
+
if (vocabCache && vocabCache.dbName === dbName)
|
|
614
|
+
return vocabCache.words;
|
|
615
|
+
const words = (0, db_helpers_js_1.dbAll)(db, "SELECT word FROM vocabulary").map((r) => r.word);
|
|
616
|
+
vocabCache = { dbName, words };
|
|
617
|
+
return words;
|
|
618
|
+
}
|
|
619
|
+
function invalidateVocabCache() {
|
|
620
|
+
vocabCache = null;
|
|
621
|
+
}
|
|
622
|
+
function populateVocabulary(db, content) {
|
|
623
|
+
const words = content.replace(constants_js_1.TURKISH_WORD_RE, " ").split(/\s+/).filter((w) => w.length >= 3).map((w) => w.toLowerCase());
|
|
624
|
+
const unique = [...new Set(words)];
|
|
625
|
+
const stmt = db.prepare("INSERT OR IGNORE INTO vocabulary (word) VALUES (?)");
|
|
626
|
+
for (const w of unique)
|
|
627
|
+
stmt.run(w);
|
|
628
|
+
}
|
|
629
|
+
function correctQuery(db, keywords) {
|
|
630
|
+
const vocab = loadVocabulary(db);
|
|
631
|
+
if (vocab.length === 0)
|
|
632
|
+
return null;
|
|
633
|
+
let corrected = false;
|
|
634
|
+
const result = keywords.map((kw) => {
|
|
635
|
+
const closest = findClosestWords(kw, vocab, 1);
|
|
636
|
+
const match = closest[0];
|
|
637
|
+
if (match !== void 0 && match !== kw) {
|
|
638
|
+
corrected = true;
|
|
639
|
+
return match;
|
|
640
|
+
}
|
|
641
|
+
return kw;
|
|
642
|
+
});
|
|
643
|
+
return corrected ? result : null;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// dist/scripts/lib/proximity.js
|
|
649
|
+
var require_proximity = __commonJS({
|
|
650
|
+
"dist/scripts/lib/proximity.js"(exports2) {
|
|
651
|
+
"use strict";
|
|
652
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
653
|
+
exports2.rerankByProximity = rerankByProximity;
|
|
654
|
+
function findMinSpan(content, terms) {
|
|
655
|
+
const lower = content.toLowerCase();
|
|
656
|
+
const positions = terms.map((t) => {
|
|
657
|
+
const pos = [];
|
|
658
|
+
let idx = lower.indexOf(t);
|
|
659
|
+
while (idx !== -1) {
|
|
660
|
+
pos.push(idx);
|
|
661
|
+
idx = lower.indexOf(t, idx + 1);
|
|
662
|
+
}
|
|
663
|
+
return pos;
|
|
664
|
+
});
|
|
665
|
+
if (positions.some((p) => p.length === 0))
|
|
666
|
+
return Infinity;
|
|
667
|
+
let minSpan = Infinity;
|
|
668
|
+
for (let i = 0; i < positions[0].length; i++) {
|
|
669
|
+
let maxPos = positions[0][i];
|
|
670
|
+
let minPos = positions[0][i];
|
|
671
|
+
for (let t = 1; t < terms.length; t++) {
|
|
672
|
+
let bestDist = Infinity;
|
|
673
|
+
let bestPos = 0;
|
|
674
|
+
for (let j = 0; j < positions[t].length; j++) {
|
|
675
|
+
const dist = Math.abs(positions[t][j] - positions[0][i]);
|
|
676
|
+
if (dist < bestDist) {
|
|
677
|
+
bestDist = dist;
|
|
678
|
+
bestPos = positions[t][j];
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (bestPos > maxPos)
|
|
682
|
+
maxPos = bestPos;
|
|
683
|
+
if (bestPos < minPos)
|
|
684
|
+
minPos = bestPos;
|
|
685
|
+
}
|
|
686
|
+
const span = maxPos - minPos;
|
|
687
|
+
if (span < minSpan)
|
|
688
|
+
minSpan = span;
|
|
689
|
+
}
|
|
690
|
+
return minSpan;
|
|
691
|
+
}
|
|
692
|
+
function rerankByProximity(results, terms) {
|
|
693
|
+
if (terms.length < 2)
|
|
694
|
+
return results;
|
|
695
|
+
return results.map((r) => {
|
|
696
|
+
const span = findMinSpan(r.content ?? "", terms);
|
|
697
|
+
const boost = span === Infinity ? 1 : 1 + 1 / (1 + span / 50);
|
|
698
|
+
return { ...r, score: r.score * boost };
|
|
699
|
+
}).sort((a, b) => b.score - a.score);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
// dist/scripts/lib/snippet.js
|
|
705
|
+
var require_snippet = __commonJS({
|
|
706
|
+
"dist/scripts/lib/snippet.js"(exports2) {
|
|
707
|
+
"use strict";
|
|
708
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
709
|
+
exports2.extractSnippet = extractSnippet;
|
|
710
|
+
function extractSnippet(content, terms, maxLen = 300) {
|
|
711
|
+
if (!content || content.length <= maxLen)
|
|
712
|
+
return content;
|
|
713
|
+
const lower = content.toLowerCase();
|
|
714
|
+
let bestPos = 0;
|
|
715
|
+
let bestScore = 0;
|
|
716
|
+
for (const term of terms) {
|
|
717
|
+
const idx = lower.indexOf(term.toLowerCase());
|
|
718
|
+
if (idx !== -1) {
|
|
719
|
+
const windowStart = Math.max(0, idx - Math.floor(maxLen / 2));
|
|
720
|
+
const windowEnd = Math.min(lower.length, idx + Math.floor(maxLen / 2));
|
|
721
|
+
const window = lower.slice(windowStart, windowEnd);
|
|
722
|
+
const termCount = terms.filter((t) => window.includes(t.toLowerCase())).length;
|
|
723
|
+
if (termCount > bestScore) {
|
|
724
|
+
bestScore = termCount;
|
|
725
|
+
bestPos = idx;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const start = Math.max(0, bestPos - Math.floor(maxLen / 3));
|
|
730
|
+
const end = Math.min(content.length, start + maxLen);
|
|
731
|
+
let snippet = content.slice(start, end);
|
|
732
|
+
if (start > 0)
|
|
733
|
+
snippet = "..." + snippet;
|
|
734
|
+
if (end < content.length)
|
|
735
|
+
snippet = snippet + "...";
|
|
736
|
+
return snippet;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// dist/scripts/lib/chunker.js
|
|
742
|
+
var require_chunker = __commonJS({
|
|
743
|
+
"dist/scripts/lib/chunker.js"(exports2) {
|
|
744
|
+
"use strict";
|
|
745
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
746
|
+
exports2.chunkMarkdown = chunkMarkdown;
|
|
747
|
+
function chunkMarkdown(markdown, options = {}) {
|
|
748
|
+
const maxChunkChars = options.maxChunkChars ?? 1e4;
|
|
749
|
+
const lines = markdown.split("\n");
|
|
750
|
+
const chunks = [];
|
|
751
|
+
let currentLines = [];
|
|
752
|
+
let currentHeading = null;
|
|
753
|
+
const headingStack = [];
|
|
754
|
+
let inCodeBlock = false;
|
|
755
|
+
function flush() {
|
|
756
|
+
const content = currentLines.join("\n").trim();
|
|
757
|
+
if (content.length === 0)
|
|
758
|
+
return;
|
|
759
|
+
const breadcrumb = headingStack.length > 0 ? headingStack.join(" > ") : "";
|
|
760
|
+
const chunk = {
|
|
761
|
+
index: 0,
|
|
762
|
+
heading: currentHeading,
|
|
763
|
+
breadcrumb,
|
|
764
|
+
content,
|
|
765
|
+
charCount: content.length
|
|
766
|
+
};
|
|
767
|
+
if (chunk.charCount > maxChunkChars) {
|
|
768
|
+
for (const c of splitOversized(chunk, maxChunkChars))
|
|
769
|
+
chunks.push(c);
|
|
770
|
+
} else {
|
|
771
|
+
chunks.push(chunk);
|
|
772
|
+
}
|
|
773
|
+
currentLines = [];
|
|
774
|
+
}
|
|
775
|
+
for (const line of lines) {
|
|
776
|
+
if (line.startsWith("```")) {
|
|
777
|
+
inCodeBlock = !inCodeBlock;
|
|
778
|
+
currentLines.push(line);
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
if (inCodeBlock) {
|
|
782
|
+
currentLines.push(line);
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)/);
|
|
786
|
+
if (headingMatch) {
|
|
787
|
+
flush();
|
|
788
|
+
currentHeading = line;
|
|
789
|
+
const level = headingMatch[1].length;
|
|
790
|
+
while (headingStack.length > 0) {
|
|
791
|
+
const top = headingStack[headingStack.length - 1];
|
|
792
|
+
const topLevel = (top.match(/^#+/) ?? [""])[0].length;
|
|
793
|
+
if (topLevel >= level)
|
|
794
|
+
headingStack.pop();
|
|
795
|
+
else
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
headingStack.push(line);
|
|
799
|
+
}
|
|
800
|
+
currentLines.push(line);
|
|
801
|
+
}
|
|
802
|
+
flush();
|
|
803
|
+
return chunks.map((c, i) => ({ ...c, index: i }));
|
|
804
|
+
}
|
|
805
|
+
function splitOversized(chunk, maxChars) {
|
|
806
|
+
const lines = chunk.content.split("\n");
|
|
807
|
+
const result = [];
|
|
808
|
+
let buffer = [];
|
|
809
|
+
let bufLen = 0;
|
|
810
|
+
for (const line of lines) {
|
|
811
|
+
if (bufLen + line.length > maxChars && buffer.length > 0) {
|
|
812
|
+
result.push({
|
|
813
|
+
index: 0,
|
|
814
|
+
heading: result.length === 0 ? chunk.heading : null,
|
|
815
|
+
breadcrumb: chunk.breadcrumb,
|
|
816
|
+
content: buffer.join("\n"),
|
|
817
|
+
charCount: bufLen
|
|
818
|
+
});
|
|
819
|
+
buffer = [];
|
|
820
|
+
bufLen = 0;
|
|
821
|
+
}
|
|
822
|
+
buffer.push(line);
|
|
823
|
+
bufLen += line.length + 1;
|
|
824
|
+
}
|
|
825
|
+
if (buffer.length > 0) {
|
|
826
|
+
result.push({
|
|
827
|
+
index: 0,
|
|
828
|
+
heading: result.length === 0 ? chunk.heading : null,
|
|
829
|
+
breadcrumb: chunk.breadcrumb,
|
|
830
|
+
content: buffer.join("\n"),
|
|
831
|
+
charCount: bufLen
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
return result;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// dist/scripts/lib/smart-snippet.js
|
|
840
|
+
var require_smart_snippet = __commonJS({
|
|
841
|
+
"dist/scripts/lib/smart-snippet.js"(exports2) {
|
|
842
|
+
"use strict";
|
|
843
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
844
|
+
exports2.extractSmartSnippet = extractSmartSnippet;
|
|
845
|
+
var snippet_js_1 = require_snippet();
|
|
846
|
+
var chunker_js_1 = require_chunker();
|
|
847
|
+
function extractSmartSnippet(db, sourcePath, fullContent, terms, maxLen = 500) {
|
|
848
|
+
if (!fullContent || fullContent.length <= maxLen) {
|
|
849
|
+
return { snippet: fullContent, heading: null };
|
|
850
|
+
}
|
|
851
|
+
let chunks;
|
|
852
|
+
try {
|
|
853
|
+
chunks = db.prepare("SELECT chunk_index, heading, breadcrumb, char_count FROM chunks WHERE source_path = ? ORDER BY chunk_index").all(sourcePath);
|
|
854
|
+
} catch {
|
|
855
|
+
return { snippet: (0, snippet_js_1.extractSnippet)(fullContent, terms, maxLen), heading: null };
|
|
856
|
+
}
|
|
857
|
+
if (chunks.length === 0) {
|
|
858
|
+
return { snippet: (0, snippet_js_1.extractSnippet)(fullContent, terms, maxLen), heading: null };
|
|
859
|
+
}
|
|
860
|
+
const parsedChunks = (0, chunker_js_1.chunkMarkdown)(fullContent);
|
|
861
|
+
const lowerTerms = terms.map((t) => t.toLowerCase());
|
|
862
|
+
let bestChunkIdx = -1;
|
|
863
|
+
let bestScore = 0;
|
|
864
|
+
for (let i = 0; i < parsedChunks.length; i++) {
|
|
865
|
+
const parsed = parsedChunks[i];
|
|
866
|
+
if (!parsed)
|
|
867
|
+
continue;
|
|
868
|
+
const chunkLower = parsed.content.toLowerCase();
|
|
869
|
+
const score = lowerTerms.filter((t) => chunkLower.includes(t)).length;
|
|
870
|
+
if (score > bestScore) {
|
|
871
|
+
bestScore = score;
|
|
872
|
+
bestChunkIdx = i;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (bestChunkIdx === -1) {
|
|
876
|
+
return { snippet: (0, snippet_js_1.extractSnippet)(fullContent, terms, maxLen), heading: null };
|
|
877
|
+
}
|
|
878
|
+
const bestParsed = parsedChunks[bestChunkIdx];
|
|
879
|
+
if (!bestParsed) {
|
|
880
|
+
return { snippet: (0, snippet_js_1.extractSnippet)(fullContent, terms, maxLen), heading: null };
|
|
881
|
+
}
|
|
882
|
+
const chunkSnippet = (0, snippet_js_1.extractSnippet)(bestParsed.content, terms, maxLen);
|
|
883
|
+
const heading = chunks[bestChunkIdx]?.heading ?? bestParsed.heading ?? null;
|
|
884
|
+
return { snippet: chunkSnippet, heading };
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
// dist/scripts/lib/search-engine.js
|
|
890
|
+
var require_search_engine = __commonJS({
|
|
891
|
+
"dist/scripts/lib/search-engine.js"(exports2) {
|
|
892
|
+
"use strict";
|
|
893
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
894
|
+
exports2.extractKeywords = extractKeywords;
|
|
895
|
+
exports2.search = search;
|
|
896
|
+
var rrf_js_1 = require_rrf();
|
|
897
|
+
var fuzzy_js_1 = require_fuzzy();
|
|
898
|
+
var proximity_js_1 = require_proximity();
|
|
899
|
+
var smart_snippet_js_1 = require_smart_snippet();
|
|
900
|
+
var constants_js_1 = require_constants();
|
|
901
|
+
function extractKeywords(text, maxKeywords) {
|
|
902
|
+
const keywords = text.replace(constants_js_1.TURKISH_WORD_RE, " ").split(/\s+/).filter((w) => w.length >= constants_js_1.STOP_WORDS_MIN_LENGTH && !constants_js_1.STOP_WORDS.has(w.toLowerCase())).map((w) => w.toLowerCase());
|
|
903
|
+
return maxKeywords ? keywords.slice(0, maxKeywords) : keywords;
|
|
904
|
+
}
|
|
905
|
+
function expandWithSynonyms(keywords, synonyms) {
|
|
906
|
+
if (!synonyms)
|
|
907
|
+
return keywords;
|
|
908
|
+
const expanded = [...keywords];
|
|
909
|
+
for (const kw of keywords) {
|
|
910
|
+
const syns = synonyms[kw];
|
|
911
|
+
if (syns)
|
|
912
|
+
expanded.push(...syns);
|
|
913
|
+
}
|
|
914
|
+
return expanded;
|
|
915
|
+
}
|
|
916
|
+
var CATEGORY_WEIGHTS = {
|
|
917
|
+
sources: 1.2,
|
|
918
|
+
analyses: 1.15,
|
|
919
|
+
domains: 1.1,
|
|
920
|
+
episodes: 1,
|
|
921
|
+
decisions: 1,
|
|
922
|
+
raw: 0.9,
|
|
923
|
+
sessions: 0.85,
|
|
924
|
+
cc_memory: 1.3
|
|
925
|
+
};
|
|
926
|
+
var INTENT_CONFIG = {
|
|
927
|
+
debug: {
|
|
928
|
+
keywords: ["debug", "fix", "hata", "bug", "error", "crash", "fail"],
|
|
929
|
+
boosts: { episodes: 1.3, raw: 1.1 }
|
|
930
|
+
},
|
|
931
|
+
research: {
|
|
932
|
+
keywords: ["ara\u015Ft\u0131r", "bul", "search", "nedir", "nas\u0131l", "compare"],
|
|
933
|
+
boosts: { sources: 1.3, analyses: 1.2 }
|
|
934
|
+
},
|
|
935
|
+
implementation: {
|
|
936
|
+
keywords: [],
|
|
937
|
+
boosts: { domains: 1.2, sessions: 1.1 }
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
var INTENT_KEYS = Object.keys(INTENT_CONFIG);
|
|
941
|
+
function detectIntent(query) {
|
|
942
|
+
const lower = query.toLowerCase();
|
|
943
|
+
for (const intent of INTENT_KEYS) {
|
|
944
|
+
if (INTENT_CONFIG[intent].keywords.some((k) => lower.includes(k)))
|
|
945
|
+
return intent;
|
|
946
|
+
}
|
|
947
|
+
return "implementation";
|
|
948
|
+
}
|
|
949
|
+
function search(db, query, options) {
|
|
950
|
+
const maxResults = options.maxResults ?? 3;
|
|
951
|
+
const keywords = extractKeywords(query);
|
|
952
|
+
if (keywords.length === 0)
|
|
953
|
+
return [];
|
|
954
|
+
const expanded = expandWithSynonyms(keywords, options.synonyms);
|
|
955
|
+
const queryStr = (0, constants_js_1.fixVersionTokens)(expanded.join(" "));
|
|
956
|
+
const limit = 20;
|
|
957
|
+
function fusedSearch(q) {
|
|
958
|
+
return (0, rrf_js_1.computeRRF)((0, rrf_js_1.searchPorter)(db, { query: q, limit, project: options.project }), (0, rrf_js_1.searchTrigram)(db, { query: q, limit, project: options.project }), { dedupByPath: true });
|
|
959
|
+
}
|
|
960
|
+
let fused = fusedSearch(queryStr);
|
|
961
|
+
if (fused.length === 0) {
|
|
962
|
+
const corrected = (0, fuzzy_js_1.correctQuery)(db, keywords);
|
|
963
|
+
if (corrected) {
|
|
964
|
+
fused = fusedSearch((0, constants_js_1.fixVersionTokens)(corrected.join(" ")));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const intent = detectIntent(query);
|
|
968
|
+
const intentBoosts = INTENT_CONFIG[intent].boosts;
|
|
969
|
+
for (const r of fused) {
|
|
970
|
+
r.score *= CATEGORY_WEIGHTS[r.category] ?? 1;
|
|
971
|
+
r.score *= intentBoosts[r.category] ?? 1;
|
|
972
|
+
}
|
|
973
|
+
fused.sort((a, b) => b.score - a.score);
|
|
974
|
+
const ranked = (0, proximity_js_1.rerankByProximity)(fused.map((r) => ({
|
|
975
|
+
slug: r.slug,
|
|
976
|
+
path: r.path,
|
|
977
|
+
title: r.title ?? "",
|
|
978
|
+
description: r.description ?? "",
|
|
979
|
+
category: r.category ?? "",
|
|
980
|
+
tags: r.tags ?? "",
|
|
981
|
+
score: r.score,
|
|
982
|
+
content: r.content
|
|
983
|
+
})), keywords);
|
|
984
|
+
return ranked.slice(0, maxResults).map((r) => {
|
|
985
|
+
const smart = r.content ? (0, smart_snippet_js_1.extractSmartSnippet)(db, r.path, r.content, keywords) : void 0;
|
|
986
|
+
return {
|
|
987
|
+
...r,
|
|
988
|
+
snippet: smart?.snippet,
|
|
989
|
+
heading: smart?.heading ?? null
|
|
990
|
+
};
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
// dist/scripts/lib/search-cache.js
|
|
997
|
+
var require_search_cache = __commonJS({
|
|
998
|
+
"dist/scripts/lib/search-cache.js"(exports2) {
|
|
999
|
+
"use strict";
|
|
1000
|
+
var __importDefault = exports2 && exports2.__importDefault || function(mod) {
|
|
1001
|
+
return mod && mod.__esModule ? mod : { "default": mod };
|
|
1002
|
+
};
|
|
1003
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1004
|
+
exports2.SearchThrottle = exports2.SearchCache = void 0;
|
|
1005
|
+
var crypto_1 = __importDefault(require("crypto"));
|
|
1006
|
+
var CLEANUP_INTERVAL_MS = 6e4;
|
|
1007
|
+
var SearchCache = class {
|
|
1008
|
+
db;
|
|
1009
|
+
ttlMs;
|
|
1010
|
+
statsReady = false;
|
|
1011
|
+
stmtHit = null;
|
|
1012
|
+
stmtMiss = null;
|
|
1013
|
+
lastCleanup = 0;
|
|
1014
|
+
constructor(db, options = {}) {
|
|
1015
|
+
this.db = db;
|
|
1016
|
+
this.ttlMs = options.ttlMs ?? 3e5;
|
|
1017
|
+
}
|
|
1018
|
+
hash(query) {
|
|
1019
|
+
return crypto_1.default.createHash("sha256").update(query).digest("hex").slice(0, 16);
|
|
1020
|
+
}
|
|
1021
|
+
ensureStatsTable() {
|
|
1022
|
+
if (this.statsReady)
|
|
1023
|
+
return;
|
|
1024
|
+
this.db.exec(`
|
|
1025
|
+
CREATE TABLE IF NOT EXISTS search_cache_stats (
|
|
1026
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
1027
|
+
hits INTEGER NOT NULL DEFAULT 0,
|
|
1028
|
+
misses INTEGER NOT NULL DEFAULT 0
|
|
1029
|
+
)
|
|
1030
|
+
`);
|
|
1031
|
+
this.db.prepare("INSERT OR IGNORE INTO search_cache_stats (id, hits, misses) VALUES (1, 0, 0)").run();
|
|
1032
|
+
this.stmtHit = this.db.prepare("UPDATE search_cache_stats SET hits = hits + 1 WHERE id = 1");
|
|
1033
|
+
this.stmtMiss = this.db.prepare("UPDATE search_cache_stats SET misses = misses + 1 WHERE id = 1");
|
|
1034
|
+
this.statsReady = true;
|
|
1035
|
+
}
|
|
1036
|
+
getStats() {
|
|
1037
|
+
this.ensureStatsTable();
|
|
1038
|
+
const row = this.db.prepare("SELECT hits, misses FROM search_cache_stats WHERE id = 1").get();
|
|
1039
|
+
const total = row.hits + row.misses;
|
|
1040
|
+
return { hits: row.hits, misses: row.misses, hitRate: total > 0 ? row.hits / total : 0 };
|
|
1041
|
+
}
|
|
1042
|
+
resetStats() {
|
|
1043
|
+
this.ensureStatsTable();
|
|
1044
|
+
this.db.prepare("UPDATE search_cache_stats SET hits = 0, misses = 0 WHERE id = 1").run();
|
|
1045
|
+
}
|
|
1046
|
+
get(query) {
|
|
1047
|
+
const h = this.hash(query);
|
|
1048
|
+
const row = this.db.prepare("SELECT results_json FROM search_cache WHERE query_hash = ? AND expires_at > ?").get(h, (/* @__PURE__ */ new Date()).toISOString());
|
|
1049
|
+
if (!row) {
|
|
1050
|
+
this.ensureStatsTable();
|
|
1051
|
+
this.stmtMiss.run();
|
|
1052
|
+
this.cleanup();
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
this.ensureStatsTable();
|
|
1056
|
+
this.stmtHit.run();
|
|
1057
|
+
return JSON.parse(row.results_json);
|
|
1058
|
+
}
|
|
1059
|
+
set(query, results) {
|
|
1060
|
+
const h = this.hash(query);
|
|
1061
|
+
const expiresAt = new Date(Date.now() + this.ttlMs).toISOString();
|
|
1062
|
+
this.db.prepare("INSERT OR REPLACE INTO search_cache (query_hash, results_json, expires_at) VALUES (?, ?, ?)").run(h, JSON.stringify(results), expiresAt);
|
|
1063
|
+
}
|
|
1064
|
+
invalidate() {
|
|
1065
|
+
this.db.exec("DELETE FROM search_cache");
|
|
1066
|
+
}
|
|
1067
|
+
cleanup() {
|
|
1068
|
+
const now = Date.now();
|
|
1069
|
+
if (now - this.lastCleanup < CLEANUP_INTERVAL_MS)
|
|
1070
|
+
return;
|
|
1071
|
+
this.lastCleanup = now;
|
|
1072
|
+
this.db.prepare("DELETE FROM search_cache WHERE expires_at < ?").run((/* @__PURE__ */ new Date()).toISOString());
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
exports2.SearchCache = SearchCache;
|
|
1076
|
+
var SearchThrottle = class {
|
|
1077
|
+
db;
|
|
1078
|
+
constructor(db) {
|
|
1079
|
+
this.db = db;
|
|
1080
|
+
}
|
|
1081
|
+
incrementCallCount(sessionId) {
|
|
1082
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1083
|
+
const row = this.db.prepare(`
|
|
1084
|
+
INSERT INTO search_throttle (session_id, call_count, last_call)
|
|
1085
|
+
VALUES (?, 1, ?)
|
|
1086
|
+
ON CONFLICT(session_id) DO UPDATE SET call_count = call_count + 1, last_call = ?
|
|
1087
|
+
RETURNING call_count
|
|
1088
|
+
`).get(sessionId, now, now);
|
|
1089
|
+
return row?.call_count ?? 1;
|
|
1090
|
+
}
|
|
1091
|
+
getMaxResults(callCount) {
|
|
1092
|
+
if (callCount <= 10)
|
|
1093
|
+
return 3;
|
|
1094
|
+
if (callCount <= 20)
|
|
1095
|
+
return 1;
|
|
1096
|
+
return 0;
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
exports2.SearchThrottle = SearchThrottle;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
// hooks/src/mindlore-search.cjs
|
|
1104
|
+
var fs = require("fs");
|
|
1105
|
+
var path = require("path");
|
|
1106
|
+
var { getAllDbs, openDatabase, extractHeadings, readHookStdin, readConfig, hookLog, incrementRecallCount, withTelemetry } = require("./lib/mindlore-common.cjs");
|
|
1107
|
+
var MAX_RESULTS = 3;
|
|
1108
|
+
var MIN_QUERY_WORDS = 3;
|
|
1109
|
+
var searchEngineMod;
|
|
20
1110
|
try {
|
|
21
|
-
searchEngineMod =
|
|
1111
|
+
searchEngineMod = require_search_engine();
|
|
22
1112
|
} catch (_err) {
|
|
23
|
-
// search-engine not built yet
|
|
24
1113
|
}
|
|
25
|
-
|
|
26
|
-
let SearchCacheMod;
|
|
1114
|
+
var SearchCacheMod;
|
|
27
1115
|
try {
|
|
28
|
-
SearchCacheMod =
|
|
1116
|
+
SearchCacheMod = require_search_cache();
|
|
29
1117
|
} catch (_err) {
|
|
30
|
-
// search-cache not built yet
|
|
31
1118
|
}
|
|
32
|
-
|
|
33
1119
|
function main() {
|
|
34
|
-
const userMessage = readHookStdin([
|
|
1120
|
+
const userMessage = readHookStdin(["prompt", "content", "message", "query"]);
|
|
35
1121
|
if (!userMessage || userMessage.length < MIN_QUERY_WORDS) return;
|
|
36
|
-
|
|
37
1122
|
const dbPaths = getAllDbs();
|
|
38
1123
|
if (dbPaths.length === 0) return;
|
|
39
|
-
|
|
40
1124
|
if (!searchEngineMod) {
|
|
41
|
-
hookLog(
|
|
1125
|
+
hookLog("search", "warn", "search-engine module not available \u2014 skipping");
|
|
42
1126
|
return;
|
|
43
1127
|
}
|
|
44
|
-
|
|
45
1128
|
const project = path.basename(process.cwd());
|
|
46
1129
|
const config = readConfig(path.dirname(dbPaths[0]));
|
|
47
|
-
const synonyms =
|
|
48
|
-
|
|
49
|
-
// Read session_id from stdin for throttling
|
|
1130
|
+
const synonyms = config && config.synonyms ? config.synonyms : {};
|
|
50
1131
|
let sessionId;
|
|
51
1132
|
try {
|
|
52
|
-
const stdinData = JSON.parse(process.env.CLAUDE_HOOK_STDIN ||
|
|
53
|
-
sessionId = stdinData.session_id ||
|
|
1133
|
+
const stdinData = JSON.parse(process.env.CLAUDE_HOOK_STDIN || "{}");
|
|
1134
|
+
sessionId = stdinData.session_id || "unknown";
|
|
54
1135
|
} catch (_) {
|
|
55
|
-
sessionId =
|
|
1136
|
+
sessionId = "unknown";
|
|
56
1137
|
}
|
|
57
|
-
|
|
58
1138
|
const allResults = [];
|
|
59
1139
|
for (const dbPath of dbPaths) {
|
|
60
1140
|
const db = openDatabase(dbPath);
|
|
61
1141
|
if (!db) continue;
|
|
62
1142
|
try {
|
|
63
|
-
// Cache + throttle
|
|
64
1143
|
let cache;
|
|
65
1144
|
let effectiveMax = MAX_RESULTS;
|
|
66
1145
|
if (SearchCacheMod) {
|
|
67
|
-
cache = new SearchCacheMod.SearchCache(db, { ttlMs:
|
|
1146
|
+
cache = new SearchCacheMod.SearchCache(db, { ttlMs: 3e5 });
|
|
68
1147
|
const throttle = new SearchCacheMod.SearchThrottle(db);
|
|
69
1148
|
const callCount = throttle.incrementCallCount(sessionId);
|
|
70
1149
|
effectiveMax = throttle.getMaxResults(callCount);
|
|
71
1150
|
if (effectiveMax === 0) {
|
|
72
|
-
hookLog(
|
|
1151
|
+
hookLog("search", "info", `Throttled (call #${callCount})`);
|
|
73
1152
|
db.close();
|
|
74
1153
|
continue;
|
|
75
1154
|
}
|
|
76
1155
|
const cached = cache.get(userMessage);
|
|
77
1156
|
if (cached) {
|
|
78
|
-
const
|
|
79
|
-
for (const r of cached) allResults.push({ ...r, baseDir });
|
|
1157
|
+
const baseDir2 = path.dirname(dbPath);
|
|
1158
|
+
for (const r of cached) allResults.push({ ...r, baseDir: baseDir2 });
|
|
80
1159
|
db.close();
|
|
81
1160
|
continue;
|
|
82
1161
|
}
|
|
83
1162
|
}
|
|
84
|
-
|
|
85
1163
|
const results = searchEngineMod.search(db, userMessage, {
|
|
86
1164
|
project,
|
|
87
1165
|
maxResults: effectiveMax,
|
|
88
|
-
synonyms
|
|
1166
|
+
synonyms
|
|
89
1167
|
});
|
|
90
|
-
|
|
91
1168
|
if (cache) cache.set(userMessage, results);
|
|
92
|
-
|
|
93
1169
|
const baseDir = path.dirname(dbPath);
|
|
94
1170
|
for (const r of results) {
|
|
95
1171
|
allResults.push({ ...r, baseDir });
|
|
96
1172
|
}
|
|
97
|
-
|
|
98
|
-
// Recall count inside loop — avoid reopening DB
|
|
99
1173
|
try {
|
|
100
1174
|
const txn = db.transaction(() => {
|
|
101
1175
|
for (const r of results) incrementRecallCount(db, r.path);
|
|
102
1176
|
});
|
|
103
1177
|
txn();
|
|
104
|
-
} catch (_e) {
|
|
1178
|
+
} catch (_e) {
|
|
1179
|
+
}
|
|
105
1180
|
} catch (err) {
|
|
106
|
-
hookLog(
|
|
1181
|
+
hookLog("search", "warn", `Search error: ${err?.message || err}`);
|
|
107
1182
|
} finally {
|
|
108
1183
|
db.close();
|
|
109
1184
|
}
|
|
110
1185
|
}
|
|
111
|
-
|
|
112
|
-
// Deduplicate by full path
|
|
113
|
-
const seen = new Set();
|
|
1186
|
+
const seen = /* @__PURE__ */ new Set();
|
|
114
1187
|
const unique = [];
|
|
115
1188
|
for (const r of allResults) {
|
|
116
1189
|
const normalized = path.resolve(r.path);
|
|
@@ -119,82 +1192,72 @@ function main() {
|
|
|
119
1192
|
unique.push(r);
|
|
120
1193
|
}
|
|
121
1194
|
}
|
|
122
|
-
|
|
123
|
-
// Sort by score descending, take top N
|
|
124
1195
|
unique.sort((a, b) => b.score - a.score);
|
|
125
1196
|
const relevant = unique.slice(0, MAX_RESULTS);
|
|
126
1197
|
if (relevant.length === 0) return;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const perResultChars = ((budget.perResult || 500) * 4);
|
|
131
|
-
const totalChars = ((budget.searchResults || 1500) * 4);
|
|
132
|
-
|
|
133
|
-
// Build output
|
|
1198
|
+
const budget = config && config.tokenBudget || {};
|
|
1199
|
+
const perResultChars = (budget.perResult || 500) * 4;
|
|
1200
|
+
const totalChars = (budget.searchResults || 1500) * 4;
|
|
134
1201
|
const output = [];
|
|
135
1202
|
let totalUsed = 0;
|
|
136
1203
|
for (const r of relevant) {
|
|
137
1204
|
if (totalUsed >= totalChars) break;
|
|
138
|
-
const relativePath = path.relative(r.baseDir, r.path).replace(/\\/g,
|
|
139
|
-
|
|
1205
|
+
const relativePath = path.relative(r.baseDir, r.path).replace(/\\/g, "/");
|
|
140
1206
|
let headings = [];
|
|
141
|
-
const contentStr = r.content ||
|
|
1207
|
+
const contentStr = r.content || "";
|
|
142
1208
|
if (contentStr) {
|
|
143
1209
|
try {
|
|
144
1210
|
headings = extractHeadings(contentStr, 3);
|
|
145
|
-
} catch (_err) {
|
|
1211
|
+
} catch (_err) {
|
|
1212
|
+
}
|
|
146
1213
|
}
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
1214
|
+
const category = r.category || path.dirname(relativePath).split("/")[0];
|
|
1215
|
+
const title = r.title || r.slug || path.basename(r.path, ".md");
|
|
1216
|
+
const description = r.description || "";
|
|
1217
|
+
const headingStr = headings.length > 0 ? `
|
|
1218
|
+
Basliklar: ${headings.join(", ")}` : "";
|
|
1219
|
+
const tagsStr = r.tags ? `
|
|
1220
|
+
Tags: ${r.tags}` : "";
|
|
154
1221
|
const snippetOrDesc = r.snippet || description;
|
|
155
|
-
const entry = `[Mindlore: ${category}/${title}] ${snippetOrDesc}
|
|
1222
|
+
const entry = `[Mindlore: ${category}/${title}] ${snippetOrDesc}
|
|
1223
|
+
Dosya: ${relativePath}${tagsStr}${headingStr}`;
|
|
156
1224
|
const truncated = entry.slice(0, perResultChars);
|
|
157
1225
|
totalUsed += truncated.length;
|
|
158
1226
|
output.push(truncated);
|
|
159
1227
|
}
|
|
160
|
-
|
|
161
1228
|
if (output.length > 0) {
|
|
162
|
-
let outputStr = output.join(
|
|
163
|
-
|
|
1229
|
+
let outputStr = output.join("\n\n") + "\n";
|
|
164
1230
|
const OFFLOAD_THRESHOLD = 10240;
|
|
165
1231
|
if (outputStr.length > OFFLOAD_THRESHOLD) {
|
|
166
1232
|
const baseDir = path.dirname(dbPaths[0]);
|
|
167
|
-
const tmpDir = path.join(baseDir,
|
|
1233
|
+
const tmpDir = path.join(baseDir, "tmp");
|
|
168
1234
|
fs.mkdirSync(tmpDir, { recursive: true });
|
|
169
|
-
|
|
170
1235
|
try {
|
|
171
|
-
const oneHourAgo = Date.now() -
|
|
172
|
-
const files = fs.readdirSync(tmpDir)
|
|
173
|
-
.filter(f => f.startsWith('search-'))
|
|
174
|
-
.map(f => ({ name: f, mtime: fs.statSync(path.join(tmpDir, f)).mtimeMs }))
|
|
175
|
-
.sort((a, b) => b.mtime - a.mtime);
|
|
1236
|
+
const oneHourAgo = Date.now() - 36e5;
|
|
1237
|
+
const files = fs.readdirSync(tmpDir).filter((f) => f.startsWith("search-")).map((f) => ({ name: f, mtime: fs.statSync(path.join(tmpDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
176
1238
|
for (let i = 0; i < files.length; i++) {
|
|
177
1239
|
if (i >= 20 || files[i].mtime < oneHourAgo) {
|
|
178
|
-
try {
|
|
1240
|
+
try {
|
|
1241
|
+
fs.unlinkSync(path.join(tmpDir, files[i].name));
|
|
1242
|
+
} catch {
|
|
1243
|
+
}
|
|
179
1244
|
}
|
|
180
1245
|
}
|
|
181
|
-
} catch {
|
|
1246
|
+
} catch {
|
|
1247
|
+
}
|
|
182
1248
|
const fileName = `search-${Date.now()}.md`;
|
|
183
1249
|
const filePath = path.join(tmpDir, fileName);
|
|
184
|
-
fs.writeFileSync(filePath, outputStr,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
hookLog('search', 'info', 'offloaded to tmp/ (' + outputStr.length + ' chars)');
|
|
1250
|
+
fs.writeFileSync(filePath, outputStr, "utf8");
|
|
1251
|
+
const summary = outputStr.slice(0, 500).replace(/\n/g, " ").trim();
|
|
1252
|
+
outputStr = `[Mindlore Search: ${outputStr.length} chars offloaded to ${filePath}]
|
|
1253
|
+
Summary: ${summary}...
|
|
1254
|
+
[Read full results: ${filePath}]`;
|
|
1255
|
+
hookLog("search", "info", "offloaded to tmp/ (" + outputStr.length + " chars)");
|
|
191
1256
|
}
|
|
192
|
-
|
|
193
1257
|
process.stdout.write(outputStr);
|
|
194
1258
|
}
|
|
195
1259
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
hookLog('mindlore-search', 'error', err?.message ?? String(err));
|
|
1260
|
+
withTelemetry("mindlore-search", main).catch((err) => {
|
|
1261
|
+
hookLog("mindlore-search", "error", err?.message ?? String(err));
|
|
199
1262
|
process.exit(0);
|
|
200
1263
|
});
|