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.
Files changed (120) hide show
  1. package/README.md +30 -3
  2. package/dist/scripts/bundle-hooks.d.ts +2 -0
  3. package/dist/scripts/bundle-hooks.d.ts.map +1 -0
  4. package/dist/scripts/bundle-hooks.js +70 -0
  5. package/dist/scripts/bundle-hooks.js.map +1 -0
  6. package/dist/scripts/init.js +0 -3
  7. package/dist/scripts/init.js.map +1 -1
  8. package/dist/scripts/lib/all-migrations.d.ts.map +1 -1
  9. package/dist/scripts/lib/all-migrations.js +3 -0
  10. package/dist/scripts/lib/all-migrations.js.map +1 -1
  11. package/dist/scripts/lib/constants.d.ts +7 -2
  12. package/dist/scripts/lib/constants.d.ts.map +1 -1
  13. package/dist/scripts/lib/constants.js +17 -22
  14. package/dist/scripts/lib/constants.js.map +1 -1
  15. package/dist/scripts/lib/mcp-tools.d.ts.map +1 -1
  16. package/dist/scripts/lib/mcp-tools.js +63 -78
  17. package/dist/scripts/lib/mcp-tools.js.map +1 -1
  18. package/dist/scripts/lib/migrations-v072.d.ts +3 -0
  19. package/dist/scripts/lib/migrations-v072.d.ts.map +1 -0
  20. package/dist/scripts/lib/migrations-v072.js +25 -0
  21. package/dist/scripts/lib/migrations-v072.js.map +1 -0
  22. package/dist/scripts/lib/relation-helpers.d.ts +15 -0
  23. package/dist/scripts/lib/relation-helpers.d.ts.map +1 -0
  24. package/dist/scripts/lib/relation-helpers.js +30 -0
  25. package/dist/scripts/lib/relation-helpers.js.map +1 -0
  26. package/dist/scripts/lib/tool-adapters/get-adapter.d.ts +21 -0
  27. package/dist/scripts/lib/tool-adapters/get-adapter.d.ts.map +1 -0
  28. package/dist/scripts/lib/tool-adapters/get-adapter.js +51 -0
  29. package/dist/scripts/lib/tool-adapters/get-adapter.js.map +1 -0
  30. package/dist/scripts/lib/tool-adapters/relate-adapter.d.ts +34 -0
  31. package/dist/scripts/lib/tool-adapters/relate-adapter.d.ts.map +1 -0
  32. package/dist/scripts/lib/tool-adapters/relate-adapter.js +43 -0
  33. package/dist/scripts/lib/tool-adapters/relate-adapter.js.map +1 -0
  34. package/dist/scripts/lib/tool-adapters/search-adapter.d.ts +5 -0
  35. package/dist/scripts/lib/tool-adapters/search-adapter.d.ts.map +1 -1
  36. package/dist/scripts/lib/tool-adapters/search-adapter.js +37 -0
  37. package/dist/scripts/lib/tool-adapters/search-adapter.js.map +1 -1
  38. package/dist/scripts/mcp-server.js +1 -1
  39. package/dist/scripts/mcp-server.js.map +1 -1
  40. package/dist/tests/dont-repeat-dedup.test.d.ts +2 -0
  41. package/dist/tests/dont-repeat-dedup.test.d.ts.map +1 -0
  42. package/dist/tests/dont-repeat-dedup.test.js +93 -0
  43. package/dist/tests/dont-repeat-dedup.test.js.map +1 -0
  44. package/dist/tests/e2e-kg-pipeline.test.d.ts +2 -0
  45. package/dist/tests/e2e-kg-pipeline.test.d.ts.map +1 -0
  46. package/dist/tests/e2e-kg-pipeline.test.js +59 -0
  47. package/dist/tests/e2e-kg-pipeline.test.js.map +1 -0
  48. package/dist/tests/helpers/db.d.ts.map +1 -1
  49. package/dist/tests/helpers/db.js +2 -1
  50. package/dist/tests/helpers/db.js.map +1 -1
  51. package/dist/tests/hook-smoke.test.js +1 -1
  52. package/dist/tests/hook-smoke.test.js.map +1 -1
  53. package/dist/tests/mcp-get-tool.test.d.ts +2 -0
  54. package/dist/tests/mcp-get-tool.test.d.ts.map +1 -0
  55. package/dist/tests/mcp-get-tool.test.js +93 -0
  56. package/dist/tests/mcp-get-tool.test.js.map +1 -0
  57. package/dist/tests/mcp-relate-tool.test.d.ts +2 -0
  58. package/dist/tests/mcp-relate-tool.test.d.ts.map +1 -0
  59. package/dist/tests/mcp-relate-tool.test.js +85 -0
  60. package/dist/tests/mcp-relate-tool.test.js.map +1 -0
  61. package/dist/tests/mcp-server.test.js +3 -1
  62. package/dist/tests/mcp-server.test.js.map +1 -1
  63. package/dist/tests/mcp-tools.test.js +20 -0
  64. package/dist/tests/mcp-tools.test.js.map +1 -1
  65. package/dist/tests/memory-relate.test.d.ts +2 -0
  66. package/dist/tests/memory-relate.test.d.ts.map +1 -0
  67. package/dist/tests/memory-relate.test.js +70 -0
  68. package/dist/tests/memory-relate.test.js.map +1 -0
  69. package/dist/tests/migrations-v063.test.js +1 -1
  70. package/dist/tests/migrations-v072.test.d.ts +2 -0
  71. package/dist/tests/migrations-v072.test.d.ts.map +1 -0
  72. package/dist/tests/migrations-v072.test.js +74 -0
  73. package/dist/tests/migrations-v072.test.js.map +1 -0
  74. package/dist/tests/plugin-cache-regression.test.d.ts +2 -0
  75. package/dist/tests/plugin-cache-regression.test.d.ts.map +1 -0
  76. package/dist/tests/plugin-cache-regression.test.js +19 -0
  77. package/dist/tests/plugin-cache-regression.test.js.map +1 -0
  78. package/dist/tests/search-hook.test.js +1 -1
  79. package/dist/tests/search-hook.test.js.map +1 -1
  80. package/hooks/cc-memory-bulk-sync.cjs +606 -0
  81. package/hooks/cc-session-sync.cjs +856 -0
  82. package/hooks/hooks.json +149 -0
  83. package/hooks/lib/mindlore-common.cjs +2 -2
  84. package/hooks/lib/secure-io.cjs +17 -0
  85. package/hooks/mindlore-cwd-changed.cjs +19 -34
  86. package/hooks/mindlore-decision-detector.cjs +40 -31
  87. package/hooks/mindlore-dont-repeat.cjs +75 -115
  88. package/hooks/mindlore-fts5-sync.cjs +15 -44
  89. package/hooks/mindlore-index.cjs +100 -101
  90. package/hooks/mindlore-model-router.cjs +20 -32
  91. package/hooks/mindlore-post-compact.cjs +26 -42
  92. package/hooks/mindlore-post-read.cjs +35 -60
  93. package/hooks/mindlore-pre-compact.cjs +55 -73
  94. package/hooks/mindlore-read-guard.cjs +28 -51
  95. package/hooks/mindlore-research-guard.cjs +63 -101
  96. package/hooks/mindlore-search.cjs +1156 -93
  97. package/hooks/mindlore-session-end.cjs +155 -276
  98. package/hooks/mindlore-session-focus.cjs +672 -110
  99. package/hooks/src/lib/constants.cjs +15 -0
  100. package/hooks/src/lib/mindlore-common.cjs +975 -0
  101. package/hooks/src/lib/mindlore-common.d.cts +72 -0
  102. package/hooks/src/lib/secure-io.cjs +17 -0
  103. package/hooks/src/lib/types.d.ts +58 -0
  104. package/hooks/src/mindlore-cwd-changed.cjs +57 -0
  105. package/hooks/src/mindlore-decision-detector.cjs +54 -0
  106. package/hooks/src/mindlore-dont-repeat.cjs +243 -0
  107. package/hooks/src/mindlore-fts5-sync.cjs +98 -0
  108. package/hooks/src/mindlore-index.cjs +230 -0
  109. package/hooks/src/mindlore-model-router.cjs +54 -0
  110. package/hooks/src/mindlore-post-compact.cjs +69 -0
  111. package/hooks/src/mindlore-post-read.cjs +106 -0
  112. package/hooks/src/mindlore-pre-compact.cjs +154 -0
  113. package/hooks/src/mindlore-read-guard.cjs +105 -0
  114. package/hooks/src/mindlore-research-guard.cjs +176 -0
  115. package/hooks/src/mindlore-search.cjs +200 -0
  116. package/hooks/src/mindlore-session-end.cjs +511 -0
  117. package/hooks/src/mindlore-session-focus.cjs +256 -0
  118. package/package.json +8 -3
  119. package/plugin.json +5 -4
  120. package/templates/config.json +1 -1
@@ -1,116 +1,1189 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
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
- * mindlore-search — UserPromptSubmit hook
6
- *
7
- * Thin wrapper over search-engine.ts pipeline.
8
- * Extracts keywords from user prompt, delegates search to modular engine,
9
- * injects top results with description + headings.
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
- const fs = require('fs');
13
- const path = require('path');
14
- const { getAllDbs, openDatabase, extractHeadings, readHookStdin, readConfig, hookLog, incrementRecallCount, withTelemetry } = require('./lib/mindlore-common.cjs');
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
- const MAX_RESULTS = 3;
17
- const MIN_QUERY_WORDS = 3;
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
- let searchEngineMod;
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 = require('../dist/scripts/lib/search-engine.js');
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 = require('../dist/scripts/lib/search-cache.js');
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(['prompt', 'content', 'message', 'query']);
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('search', 'warn', 'search-engine module not available skipping');
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 = (config && config.synonyms) ? config.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 || 'unknown';
1133
+ const stdinData = JSON.parse(process.env.CLAUDE_HOOK_STDIN || "{}");
1134
+ sessionId = stdinData.session_id || "unknown";
54
1135
  } catch (_) {
55
- sessionId = 'unknown';
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: 300000 });
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('search', 'info', `Throttled (call #${callCount})`);
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 baseDir = path.dirname(dbPath);
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) { /* graceful */ }
1178
+ } catch (_e) {
1179
+ }
105
1180
  } catch (err) {
106
- hookLog('search', 'warn', `Search error: ${err?.message || err}`);
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
- // Token budget from config
129
- const budget = (config && config.tokenBudget) || {};
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) { /* skip */ }
1211
+ } catch (_err) {
1212
+ }
146
1213
  }
147
-
148
- const category = r.category || path.dirname(relativePath).split('/')[0];
149
- const title = r.title || r.slug || path.basename(r.path, '.md');
150
- const description = r.description || '';
151
-
152
- const headingStr = headings.length > 0 ? `\nBasliklar: ${headings.join(', ')}` : '';
153
- const tagsStr = r.tags ? `\nTags: ${r.tags}` : '';
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}\nDosya: ${relativePath}${tagsStr}${headingStr}`;
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('\n\n') + '\n';
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, 'tmp');
1233
+ const tmpDir = path.join(baseDir, "tmp");
168
1234
  fs.mkdirSync(tmpDir, { recursive: true });
169
-
170
1235
  try {
171
- const oneHourAgo = Date.now() - 3600000;
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 { fs.unlinkSync(path.join(tmpDir, files[i].name)); } catch { /* ignore */ }
1240
+ try {
1241
+ fs.unlinkSync(path.join(tmpDir, files[i].name));
1242
+ } catch {
1243
+ }
179
1244
  }
180
1245
  }
181
- } catch { /* cleanup is best-effort */ }
1246
+ } catch {
1247
+ }
182
1248
  const fileName = `search-${Date.now()}.md`;
183
1249
  const filePath = path.join(tmpDir, fileName);
184
- fs.writeFileSync(filePath, outputStr, 'utf8');
185
-
186
- const summary = outputStr.slice(0, 500).replace(/\n/g, ' ').trim();
187
- outputStr = `[Mindlore Search: ${outputStr.length} chars offloaded to ${filePath}]\n` +
188
- `Summary: ${summary}...\n` +
189
- `[Read full results: ${filePath}]`;
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
- withTelemetry('mindlore-search', main).catch(err => {
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
  });