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,63 +1,46 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * mindlore-research-guard — PreToolUse (Agent) hook
6
- *
7
- * Before spawning a researcher agent, checks FTS5 for existing knowledge.
8
- * - High quality + recent (30 days) match → exit 2 (block)
9
- * - Old or low quality match → exit 0 with warning (additionalContext)
10
- * - No match → silent pass
11
- *
12
- * Prevents redundant web research when knowledge already exists in DB.
13
- */
14
-
15
- const fs = require('fs');
16
- const path = require('path');
17
- const { getAllDbs, requireDatabase, extractKeywords, sanitizeKeyword, hookLog, withTelemetrySync } = require('./lib/mindlore-common.cjs');
18
-
19
- // Keywords that signal a research/web-search intent in agent prompts
20
- // Note: entries with dots/stars are regex patterns, rest are literals
21
- const RESEARCH_SIGNALS = [
22
- 'research', 'araştır', 'arastir', 'investigate', 'search for',
23
- 'web search', 'websearch', 'webfetch', 'fetch.*url', 'look up',
24
- 'find out', 'check.*docs', 'documentation.*for',
2
+ "use strict";
3
+
4
+ // hooks/src/mindlore-research-guard.cjs
5
+ var fs = require("fs");
6
+ var path = require("path");
7
+ var { getAllDbs, requireDatabase, extractKeywords, sanitizeKeyword, hookLog, withTelemetrySync } = require("./lib/mindlore-common.cjs");
8
+ var RESEARCH_SIGNALS = [
9
+ "research",
10
+ "ara\u015Ft\u0131r",
11
+ "arastir",
12
+ "investigate",
13
+ "search for",
14
+ "web search",
15
+ "websearch",
16
+ "webfetch",
17
+ "fetch.*url",
18
+ "look up",
19
+ "find out",
20
+ "check.*docs",
21
+ "documentation.*for"
25
22
  ];
26
- const RESEARCH_REGEX = new RegExp(RESEARCH_SIGNALS.join('|'), 'i');
27
-
28
- // Exclude ingest/internal operations (they intentionally fetch URLs)
29
- const EXCLUDE_REGEX = /\[mindlore:|\bmindlore-ingest\b|ingest.*url|save.*raw|\[research-override\]/i;
30
-
31
- const MAX_AGE_DAYS = 30;
32
-
23
+ var RESEARCH_REGEX = new RegExp(RESEARCH_SIGNALS.join("|"), "i");
24
+ var EXCLUDE_REGEX = /\[mindlore:|\bmindlore-ingest\b|ingest.*url|save.*raw|\[research-override\]/i;
25
+ var MAX_AGE_DAYS = 30;
33
26
  function isRecent(dateStr) {
34
27
  if (!dateStr) return false;
35
28
  const d = new Date(dateStr);
36
29
  if (isNaN(d.getTime())) return false;
37
- const diff = (Date.now() - d.getTime()) / (1000 * 60 * 60 * 24);
30
+ const diff = (Date.now() - d.getTime()) / (1e3 * 60 * 60 * 24);
38
31
  return diff <= MAX_AGE_DAYS;
39
32
  }
40
-
41
- /**
42
- * Search FTS5 using a single OR query instead of per-path×keyword loop.
43
- * Returns top matches with quality and date from FTS5 columns (no file I/O).
44
- */
45
33
  function searchDbs(keywords) {
46
34
  const Database = requireDatabase();
47
35
  if (!Database) return [];
48
-
49
36
  const sanitized = keywords.map(sanitizeKeyword).filter(Boolean);
50
37
  if (sanitized.length === 0) return [];
51
-
52
- const matchQuery = sanitized.join(' OR ');
38
+ const matchQuery = sanitized.join(" OR ");
53
39
  const dbPaths = getAllDbs();
54
40
  const results = [];
55
-
56
41
  for (const dbPath of dbPaths) {
57
42
  try {
58
43
  const db = new Database(dbPath, { readonly: true });
59
-
60
- // Single FTS5 query — O(1) instead of O(paths × keywords)
61
44
  const rows = db.prepare(
62
45
  `SELECT path, slug, title, description, quality, date_captured, rank
63
46
  FROM mindlore_fts
@@ -65,112 +48,91 @@ function searchDbs(keywords) {
65
48
  ORDER BY rank
66
49
  LIMIT 10`
67
50
  ).all(matchQuery);
68
-
69
51
  for (const row of rows) {
70
- const quality = (row.quality || 'medium').toLowerCase();
52
+ const quality = (row.quality || "medium").toLowerCase();
71
53
  const date_captured = row.date_captured || null;
72
-
73
54
  results.push({
74
- slug: row.slug || path.basename(row.path, '.md'),
75
- title: row.title || row.description || row.slug || '',
55
+ slug: row.slug || path.basename(row.path, ".md"),
56
+ title: row.title || row.description || row.slug || "",
76
57
  quality,
77
58
  date_captured,
78
59
  recent: isRecent(date_captured),
79
- rank: row.rank,
60
+ rank: row.rank
80
61
  });
81
62
  }
82
-
83
63
  db.close();
84
- } catch (_err) { /* db open or query failed */ }
64
+ } catch (_err) {
65
+ }
85
66
  }
86
-
87
- // Sort by rank (lower = better match in FTS5)
88
67
  results.sort((a, b) => a.rank - b.rank);
89
68
  return results.slice(0, 5);
90
69
  }
91
-
92
70
  function main() {
93
71
  let input;
94
72
  try {
95
- const raw = fs.readFileSync(0, 'utf8').trim();
73
+ const raw = fs.readFileSync(0, "utf8").trim();
96
74
  if (!raw) return;
97
75
  input = JSON.parse(raw);
98
76
  } catch (_err) {
99
77
  return;
100
78
  }
101
-
102
- const toolName = input.tool_name || '';
103
- if (toolName !== 'Agent') return;
104
-
79
+ const toolName = input.tool_name || "";
80
+ if (toolName !== "Agent") return;
105
81
  const toolInput = input.tool_input || {};
106
-
107
- // Only block agents with web access — let local-only agents pass
108
- const WEB_CAPABLE_TYPES = ['researcher', 'general-purpose'];
82
+ const WEB_CAPABLE_TYPES = ["researcher", "general-purpose"];
109
83
  const LOCAL_ONLY_TYPES = [
110
- 'Explore', 'coder', 'code-reviewer', 'Plan',
111
- 'bug-analyzer', 'security-reviewer', 'contrarian',
112
- 'scope-guardian', 'quality-gate', 'test-runner',
84
+ "Explore",
85
+ "coder",
86
+ "code-reviewer",
87
+ "Plan",
88
+ "bug-analyzer",
89
+ "security-reviewer",
90
+ "contrarian",
91
+ "scope-guardian",
92
+ "quality-gate",
93
+ "test-runner"
113
94
  ];
114
- const subagentType = toolInput.subagent_type || '';
115
- const description = (toolInput.description || '').toLowerCase();
116
-
117
- // Known local-only agent → always pass
95
+ const subagentType = toolInput.subagent_type || "";
96
+ const description = (toolInput.description || "").toLowerCase();
118
97
  if (LOCAL_ONLY_TYPES.includes(subagentType)) return;
119
-
120
- // Known web-capable agent → continue to FTS5 check
121
- // Unknown or empty subagent_type → check description for research intent
122
98
  if (subagentType && !WEB_CAPABLE_TYPES.includes(subagentType)) return;
123
-
124
- // If no subagent_type, check description for web research intent (reuse RESEARCH_REGEX)
125
99
  if (!subagentType && !RESEARCH_REGEX.test(description)) return;
126
-
127
- const prompt = (toolInput.prompt || '') + ' ' + (toolInput.description || '');
128
-
129
- // Skip mindlore internal operations and explicit overrides
100
+ const prompt = (toolInput.prompt || "") + " " + (toolInput.description || "");
130
101
  if (EXCLUDE_REGEX.test(prompt)) return;
131
-
132
- // If subagent_type is a known research type, skip prompt-level regex check
133
- // Otherwise require research signals in the prompt text
134
102
  const isKnownResearchType = WEB_CAPABLE_TYPES.includes(subagentType);
135
103
  if (!isKnownResearchType && !RESEARCH_REGEX.test(prompt)) return;
136
-
137
104
  const keywords = extractKeywords(prompt, 10);
138
105
  if (keywords.length < 2) return;
139
-
140
106
  const matches = searchDbs(keywords);
141
107
  if (matches.length === 0) return;
142
-
143
- // Prevents false positives like "claude-code-repo" matching on generic words
144
108
  const lcKeywords = keywords.map((k) => k.toLowerCase());
145
109
  const relevantMatches = matches.filter((m) => {
146
110
  const haystack = `${m.slug} ${m.title}`.toLowerCase();
147
111
  const overlap = lcKeywords.filter((k) => haystack.includes(k));
148
112
  return overlap.length >= 2;
149
113
  });
150
-
151
114
  if (relevantMatches.length === 0) return;
152
-
153
- // Check for high-quality recent matches among relevant ones
154
- const strongMatches = relevantMatches.filter((m) => m.quality === 'high' && m.recent);
155
-
115
+ const strongMatches = relevantMatches.filter((m) => m.quality === "high" && m.recent);
156
116
  if (strongMatches.length > 0) {
157
- const slugList = strongMatches.map((m) => ` - ${m.slug} (${m.title})`).join('\n');
158
- const msg = `[mindlore-research-guard] BLOK: Bu konuda guncel, yuksek kaliteli bilgi DB'de zaten var.\n` +
159
- `Once mevcut bilgiyi oku:\n${slugList}\n` +
160
- `Eger bilgi yetersizse, prompt'a "[research-override]" ekleyerek tekrar dene.`;
117
+ const slugList2 = strongMatches.map((m) => ` - ${m.slug} (${m.title})`).join("\n");
118
+ const msg = `[mindlore-research-guard] BLOK: Bu konuda guncel, yuksek kaliteli bilgi DB'de zaten var.
119
+ Once mevcut bilgiyi oku:
120
+ ${slugList2}
121
+ Eger bilgi yetersizse, prompt'a "[research-override]" ekleyerek tekrar dene.`;
161
122
  process.stderr.write(msg);
162
123
  process.exit(2);
163
124
  }
164
-
165
- // WARN: relevant but old or low-quality matches exist
166
- const slugList = relevantMatches.map((m) => `${m.slug} (${m.quality}, ${m.date_captured || 'tarih yok'})`).join(', ');
125
+ const slugList = relevantMatches.map((m) => `${m.slug} (${m.quality}, ${m.date_captured || "tarih yok"})`).join(", ");
167
126
  const output = {
168
127
  hookSpecificOutput: {
169
- hookEventName: 'PreToolUse',
170
- additionalContext: `[mindlore-research-guard] DB'de ilgili bilgi var ama eski/dusuk kalite: ${slugList}. Guncelleme gerekebilir arastirma sonrasi DB'yi guncelle.`,
171
- },
128
+ hookEventName: "PreToolUse",
129
+ additionalContext: `[mindlore-research-guard] DB'de ilgili bilgi var ama eski/dusuk kalite: ${slugList}. Guncelleme gerekebilir \u2014 arastirma sonrasi DB'yi guncelle.`
130
+ }
172
131
  };
173
132
  process.stdout.write(JSON.stringify(output));
174
133
  }
175
-
176
- try { withTelemetrySync('mindlore-research-guard', main); } catch (err) { hookLog('research-guard', 'error', err?.message ?? String(err)); }
134
+ try {
135
+ withTelemetrySync("mindlore-research-guard", main);
136
+ } catch (err) {
137
+ hookLog("research-guard", "error", err?.message ?? String(err));
138
+ }