mindlore 0.6.4 → 0.6.5

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 (82) hide show
  1. package/README.md +1 -1
  2. package/dist/scripts/cc-memory-bulk-sync.js +1 -1
  3. package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
  4. package/dist/scripts/cc-session-sync.js +2 -2
  5. package/dist/scripts/cc-session-sync.js.map +1 -1
  6. package/dist/scripts/fetch-raw.js +17 -8
  7. package/dist/scripts/fetch-raw.js.map +1 -1
  8. package/dist/scripts/init.js +8 -8
  9. package/dist/scripts/init.js.map +1 -1
  10. package/dist/scripts/lib/daemon.d.ts.map +1 -1
  11. package/dist/scripts/lib/daemon.js +3 -0
  12. package/dist/scripts/lib/daemon.js.map +1 -1
  13. package/dist/scripts/lib/input-validation.d.ts +5 -0
  14. package/dist/scripts/lib/input-validation.d.ts.map +1 -0
  15. package/dist/scripts/lib/input-validation.js +48 -0
  16. package/dist/scripts/lib/input-validation.js.map +1 -0
  17. package/dist/scripts/lib/privacy-filter.d.ts.map +1 -1
  18. package/dist/scripts/lib/privacy-filter.js +3 -0
  19. package/dist/scripts/lib/privacy-filter.js.map +1 -1
  20. package/dist/scripts/lib/rrf.d.ts.map +1 -1
  21. package/dist/scripts/lib/rrf.js +10 -10
  22. package/dist/scripts/lib/rrf.js.map +1 -1
  23. package/dist/scripts/lib/search-cache.d.ts +1 -0
  24. package/dist/scripts/lib/search-cache.d.ts.map +1 -1
  25. package/dist/scripts/lib/search-cache.js +6 -0
  26. package/dist/scripts/lib/search-cache.js.map +1 -1
  27. package/dist/scripts/lib/search-engine.d.ts +1 -1
  28. package/dist/scripts/lib/search-engine.d.ts.map +1 -1
  29. package/dist/scripts/lib/search-engine.js +3 -2
  30. package/dist/scripts/lib/search-engine.js.map +1 -1
  31. package/dist/scripts/mindlore-daemon.js +1 -3
  32. package/dist/scripts/mindlore-daemon.js.map +1 -1
  33. package/dist/scripts/mindlore-obsidian.js +4 -0
  34. package/dist/scripts/mindlore-obsidian.js.map +1 -1
  35. package/dist/tests/fetch-raw-security.test.d.ts +2 -0
  36. package/dist/tests/fetch-raw-security.test.d.ts.map +1 -0
  37. package/dist/tests/fetch-raw-security.test.js +72 -0
  38. package/dist/tests/fetch-raw-security.test.js.map +1 -0
  39. package/dist/tests/fetch-raw.test.js +4 -4
  40. package/dist/tests/fetch-raw.test.js.map +1 -1
  41. package/dist/tests/fts5.test.js +0 -22
  42. package/dist/tests/fts5.test.js.map +1 -1
  43. package/dist/tests/input-validation.test.d.ts +2 -0
  44. package/dist/tests/input-validation.test.d.ts.map +1 -0
  45. package/dist/tests/input-validation.test.js +113 -0
  46. package/dist/tests/input-validation.test.js.map +1 -0
  47. package/dist/tests/privacy-filter.test.js +25 -50
  48. package/dist/tests/privacy-filter.test.js.map +1 -1
  49. package/dist/tests/search-hook.test.js +0 -44
  50. package/dist/tests/search-hook.test.js.map +1 -1
  51. package/dist/tests/sec-regression.test.d.ts +2 -0
  52. package/dist/tests/sec-regression.test.d.ts.map +1 -0
  53. package/dist/tests/sec-regression.test.js +174 -0
  54. package/dist/tests/sec-regression.test.js.map +1 -0
  55. package/dist/tests/stop-words.test.js +26 -0
  56. package/dist/tests/stop-words.test.js.map +1 -1
  57. package/hooks/lib/mindlore-common.cjs +23 -4
  58. package/hooks/mindlore-fts5-sync.cjs +4 -3
  59. package/hooks/mindlore-index.cjs +6 -7
  60. package/hooks/mindlore-pre-compact.cjs +5 -4
  61. package/hooks/mindlore-session-end.cjs +10 -10
  62. package/hooks/mindlore-session-focus.cjs +11 -1
  63. package/package.json +1 -1
  64. package/plugin.json +1 -1
  65. package/templates/SCHEMA.md +10 -108
  66. package/templates/config.json +1 -1
  67. package/dist/scripts/lib/hybrid-search.d.ts +0 -62
  68. package/dist/scripts/lib/hybrid-search.d.ts.map +0 -1
  69. package/dist/scripts/lib/hybrid-search.js +0 -171
  70. package/dist/scripts/lib/hybrid-search.js.map +0 -1
  71. package/dist/tests/hybrid-search.test.d.ts +0 -2
  72. package/dist/tests/hybrid-search.test.d.ts.map +0 -1
  73. package/dist/tests/hybrid-search.test.js +0 -139
  74. package/dist/tests/hybrid-search.test.js.map +0 -1
  75. package/dist/tests/index-cli-embed.test.d.ts +0 -7
  76. package/dist/tests/index-cli-embed.test.d.ts.map +0 -1
  77. package/dist/tests/index-cli-embed.test.js +0 -128
  78. package/dist/tests/index-cli-embed.test.js.map +0 -1
  79. package/dist/tests/search-cli-hybrid.test.d.ts +0 -6
  80. package/dist/tests/search-cli-hybrid.test.d.ts.map +0 -1
  81. package/dist/tests/search-cli-hybrid.test.js +0 -103
  82. package/dist/tests/search-cli-hybrid.test.js.map +0 -1
@@ -44,6 +44,21 @@ function getActiveMindloreDir() {
44
44
  return globalDir();
45
45
  }
46
46
 
47
+ function isInsideMindloreDir(resolvedPath) {
48
+ return resolvedPath.includes(path.sep + MINDLORE_DIR + path.sep)
49
+ || resolvedPath.endsWith(path.sep + MINDLORE_DIR);
50
+ }
51
+
52
+ function extractMindloreBaseDir(resolvedPath) {
53
+ const sepDir = path.sep + MINDLORE_DIR;
54
+ let idx = resolvedPath.lastIndexOf(sepDir + path.sep);
55
+ if (idx === -1 && resolvedPath.endsWith(sepDir)) {
56
+ idx = resolvedPath.length - sepDir.length;
57
+ }
58
+ if (idx === -1) return null;
59
+ return resolvedPath.slice(0, idx + sepDir.length);
60
+ }
61
+
47
62
  /**
48
63
  * Return the single global mindlore DB path.
49
64
  * v0.3.3: multi-DB layered search removed — single global DB with project column.
@@ -656,7 +671,9 @@ function _rotateFile(filePath, maxBytes, keepLines) {
656
671
  const stat = fs.statSync(filePath);
657
672
  if (stat.size > maxBytes) {
658
673
  const lines = fs.readFileSync(filePath, 'utf8').trim().split('\n');
659
- fs.writeFileSync(filePath, lines.slice(-keepLines).join('\n') + '\n');
674
+ const tmpPath = filePath + '.tmp';
675
+ fs.writeFileSync(tmpPath, lines.slice(-keepLines).join('\n') + '\n', { mode: 0o600 });
676
+ fs.renameSync(tmpPath, filePath);
660
677
  }
661
678
  } catch { /* file may not exist yet */ }
662
679
  }
@@ -666,7 +683,7 @@ let _telDirEnsured = false;
666
683
  function _writeTelemetry({ hookName, duration_ms, ok, extra }) {
667
684
  try {
668
685
  if (!_telDirEnsured) {
669
- fs.mkdirSync(GLOBAL_MINDLORE_DIR, { recursive: true });
686
+ fs.mkdirSync(GLOBAL_MINDLORE_DIR, { recursive: true, mode: 0o700 });
670
687
  _telDirEnsured = true;
671
688
  }
672
689
  const telPath = path.join(GLOBAL_MINDLORE_DIR, 'telemetry.jsonl');
@@ -799,6 +816,9 @@ module.exports = {
799
816
  isDaemonRunning,
800
817
  getDaemonPortFile,
801
818
  getDaemonPidFile,
819
+ _rotateFile,
820
+ isInsideMindloreDir,
821
+ extractMindloreBaseDir,
802
822
  // Telemetry (v0.6.0)
803
823
  withTelemetry,
804
824
  withTelemetrySync,
@@ -851,9 +871,8 @@ function getUnpromotedRawFiles(baseDir) {
851
871
  }
852
872
 
853
873
  function isDaemonRunning(pidFile) {
854
- if (!fs.existsSync(pidFile)) return { running: false };
855
- const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
856
874
  try {
875
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
857
876
  process.kill(pid, 0);
858
877
  return { running: true, pid };
859
878
  } catch {
@@ -13,13 +13,14 @@
13
13
 
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
- const { MINDLORE_DIR, DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry, SQL_FTS_SESSIONS_INSERT, isSessionCategory } = require('./lib/mindlore-common.cjs');
16
+ const { DB_NAME, sha256, openDatabase, getAllMdFiles, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getActiveMindloreDir, getProjectName, resolveProject, hookLog, withTelemetry, SQL_FTS_SESSIONS_INSERT, isSessionCategory, isInsideMindloreDir } = require('./lib/mindlore-common.cjs');
17
17
 
18
18
  function main() {
19
19
  const filePath = readHookStdin(['path', 'file_path']);
20
20
 
21
- // Only trigger on .mindlore/ changes (empty filePath = skip)
22
- if (!filePath || !filePath.includes(MINDLORE_DIR)) return;
21
+ if (!filePath) return;
22
+ const resolved = path.resolve(filePath);
23
+ if (!isInsideMindloreDir(resolved)) return;
23
24
 
24
25
  // Skip if this is a single .md file change — mindlore-index.cjs handles those.
25
26
  // This hook is for bulk changes (git pull, manual batch edits).
@@ -10,7 +10,7 @@
10
10
 
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
- const { MINDLORE_DIR, DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, resolveProject, globalDir, hookLog, withTelemetry } = require('./lib/mindlore-common.cjs');
13
+ const { DB_NAME, SKIP_FILES, sha256, openDatabase, parseFrontmatter, extractFtsMetadata, insertFtsRow, readHookStdin, getProjectName, resolveProject, globalDir, hookLog, withTelemetry, isInsideMindloreDir, extractMindloreBaseDir } = require('./lib/mindlore-common.cjs');
14
14
 
15
15
  function invalidateSearchCache(db) {
16
16
  try { db.exec('DELETE FROM search_cache'); } catch (_) { /* table may not exist */ }
@@ -23,7 +23,7 @@ function main() {
23
23
  // Only process .md files inside .mindlore/ (resolved path check prevents traversal)
24
24
  if (!filePath.endsWith('.md')) return;
25
25
  const resolvedFile = path.resolve(filePath);
26
- if (!resolvedFile.includes(path.sep + MINDLORE_DIR + path.sep) && !resolvedFile.includes(path.sep + MINDLORE_DIR)) {
26
+ if (!isInsideMindloreDir(resolvedFile)) {
27
27
  // CC memory path (~/.claude/projects/*/memory/*.md) — index to global mindlore DB
28
28
  const isCcMemory = resolvedFile.includes(path.sep + '.claude' + path.sep + 'projects' + path.sep)
29
29
  && resolvedFile.includes(path.sep + 'memory' + path.sep)
@@ -37,9 +37,8 @@ function main() {
37
37
 
38
38
  const fileName = path.basename(filePath);
39
39
 
40
- // Find the .mindlore dir from the file path
41
- const mindloreIdx = filePath.indexOf(MINDLORE_DIR);
42
- const baseDir = filePath.slice(0, mindloreIdx + MINDLORE_DIR.length);
40
+ const baseDir = extractMindloreBaseDir(resolvedFile);
41
+ if (!baseDir) return;
43
42
  const dbPath = path.join(baseDir, DB_NAME);
44
43
 
45
44
  if (!fs.existsSync(dbPath)) return;
@@ -165,9 +164,9 @@ function indexCcMemory(filePath) {
165
164
 
166
165
  // Copy to ~/.mindlore/memory/{project}/ for git-sync + obsidian
167
166
  const memoryDir = path.join(globalBase, 'memory', projectScope || '_global');
168
- fs.mkdirSync(memoryDir, { recursive: true });
167
+ fs.mkdirSync(memoryDir, { recursive: true, mode: 0o700 });
169
168
  const destPath = path.join(memoryDir, path.basename(filePath));
170
- fs.writeFileSync(destPath, cleaned, 'utf8');
169
+ fs.writeFileSync(destPath, cleaned, { encoding: 'utf8', mode: 0o600 });
171
170
  } finally {
172
171
  db.close();
173
172
  }
@@ -45,10 +45,11 @@ function collectRecentEpisodes(baseDir) {
45
45
 
46
46
  function collectGitDiff() {
47
47
  try {
48
- const { execSync } = require('child_process');
49
- const diffStat = execSync('git diff --stat HEAD 2>/dev/null || echo ""', {
50
- encoding: 'utf8', timeout: 2000, windowsHide: true,
51
- }).trim();
48
+ const { execFileSync } = require('child_process');
49
+ let diffStat = '';
50
+ try {
51
+ diffStat = execFileSync('git', ['diff', '--stat', 'HEAD'], { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
52
+ } catch { diffStat = ''; }
52
53
  if (diffStat) return ['## Changed Files (uncommitted)', '```', diffStat, '```'];
53
54
  return [];
54
55
  } catch (_err) {
@@ -12,7 +12,7 @@
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
14
  const os = require('os');
15
- const { execSync, execFileSync, spawn } = require('child_process');
15
+ const { execFileSync, spawn } = require('child_process');
16
16
  const { findMindloreDir, globalDir, getProjectName, openDatabase, ensureEpisodesTable, hasEpisodesTable, insertBareEpisode, insertFtsRow, hookLog, SHARED_EXPORT_DIRS, resolveWin32Bin, withTelemetry, getUnpromotedRawFiles } = require('./lib/mindlore-common.cjs');
17
17
 
18
18
  const EXPORT_DIRS = SHARED_EXPORT_DIRS;
@@ -117,7 +117,7 @@ function formatDate(date) {
117
117
  function getRecentGitInfo() {
118
118
  try {
119
119
  // --name-only includes file names after each commit entry
120
- const raw = execSync('git log --oneline -5 --name-only', {
120
+ const raw = execFileSync('git', ['log', '--oneline', '-5', '--name-only'], {
121
121
  encoding: 'utf8',
122
122
  timeout: 5000,
123
123
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -220,7 +220,7 @@ function main() {
220
220
 
221
221
  sections.push('');
222
222
 
223
- fs.writeFileSync(deltaPath, sections.join('\n'), 'utf8');
223
+ fs.writeFileSync(deltaPath, sections.join('\n'), { encoding: 'utf8', mode: 0o600 });
224
224
 
225
225
  // Append to log.md
226
226
  const logPath = path.join(baseDir, 'log.md');
@@ -235,7 +235,7 @@ function main() {
235
235
  try {
236
236
  const workerData = JSON.stringify({ baseDir, project, commits, changedFiles, reads });
237
237
  const tmpFile = path.join(os.tmpdir(), `mindlore-worker-${Date.now()}.json`);
238
- fs.writeFileSync(tmpFile, workerData, 'utf8');
238
+ fs.writeFileSync(tmpFile, workerData, { encoding: 'utf8', mode: 0o600 });
239
239
  // Use system node instead of process.execPath — CC's embedded Node
240
240
  // may not work as a standalone binary for detached worker processes.
241
241
  // Resolve full path to avoid shell:true deprecation warning on Windows.
@@ -377,7 +377,7 @@ function writeEpisodeFile(baseDir, project, commits, changedFiles, reads) {
377
377
  lines.push('');
378
378
  }
379
379
 
380
- fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
380
+ fs.writeFileSync(filePath, lines.join('\n'), { encoding: 'utf8', mode: 0o600 });
381
381
  }
382
382
 
383
383
  let _obsidianHelpersCache = undefined; // undefined = not yet attempted
@@ -474,7 +474,7 @@ function syncObsidian(baseDir) {
474
474
  if (exported > 0) {
475
475
  config.obsidian.lastExport = new Date().toISOString();
476
476
  config.obsidian.lastExportCount = exported;
477
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
477
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: 'utf8', mode: 0o600 });
478
478
  }
479
479
  } catch (err) {
480
480
  hookLog('session-end', 'error', `obsidian internal: ${err?.message ?? err}`);
@@ -500,16 +500,16 @@ function syncGlobalRepo() {
500
500
  const execOpts = (timeout) => ({ cwd: gDir, encoding: 'utf8', timeout, stdio: 'pipe', windowsHide: true });
501
501
 
502
502
  // Check for changes
503
- const status = execSync(`"${git}" status --porcelain`, execOpts(5000)).trim();
503
+ const status = execFileSync(git, ['status', '--porcelain'], execOpts(5000)).trim();
504
504
  if (!status) return; // nothing to commit
505
505
 
506
- execSync(`"${git}" add *.md mindlore.db diary/ sources/ domains/ analyses/ decisions/ raw/ connections/ insights/ learnings/`, execOpts(10000));
506
+ execFileSync(git, ['add', '*.md', 'mindlore.db', 'diary/', 'sources/', 'domains/', 'analyses/', 'decisions/', 'raw/', 'connections/', 'insights/', 'learnings/'], execOpts(10000));
507
507
  const now = new Date().toISOString().slice(0, 19);
508
- execSync(`"${git}" commit -m "mindlore auto-sync ${now}"`, execOpts(15000));
508
+ execFileSync(git, ['commit', '-m', `mindlore auto-sync ${now}`], execOpts(15000));
509
509
 
510
510
  // Push — graceful fail if no remote or offline
511
511
  try {
512
- execSync(`"${git}" push`, execOpts(30000));
512
+ execFileSync(git, ['push'], execOpts(30000));
513
513
  } catch (_pushErr) {
514
514
  hookLog('session-end', 'warn', 'git push failed (offline?): ' + (_pushErr?.message ?? '').slice(0, 100));
515
515
  }
@@ -12,6 +12,16 @@ const fs = require('fs');
12
12
  const path = require('path');
13
13
  const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, withTelemetry, withTimeoutDb, listSnapshots, isCorruptionError, recoverCorruptDb } = require('./lib/mindlore-common.cjs');
14
14
 
15
+ function truncateCommits(content) {
16
+ const commitMatch = content.match(/(## Commits\n)((?:- [^\n]+\n?)+)/);
17
+ if (!commitMatch) return content;
18
+ const lines = commitMatch[2].trim().split('\n');
19
+ if (lines.length <= 5) return content;
20
+ const kept = lines.slice(0, 5).join('\n');
21
+ const truncated = kept + `\n- ...ve ${lines.length - 5} commit daha`;
22
+ return content.replace(commitMatch[2].trim(), truncated);
23
+ }
24
+
15
25
  function tryOpenDb(dbPath) {
16
26
  return openDatabase(dbPath, { readonly: true });
17
27
  }
@@ -107,7 +117,7 @@ function main() {
107
117
  const deltaProject = meta.project || null;
108
118
  const currentProject = getProjectName();
109
119
  if (!deltaProject || deltaProject.toLowerCase() === currentProject.toLowerCase()) {
110
- output.push(`[Mindlore Delta: ${latestName}]\n${deltaContent}`);
120
+ output.push(`[Mindlore Delta: ${latestName}]\n${truncateCommits(deltaContent)}`);
111
121
  }
112
122
  }
113
123
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindlore",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "AI-native knowledge system for Claude Code",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mindlore",
3
3
  "description": "AI-native knowledge system for Claude Code. Persistent, searchable, evolving knowledge base with FTS5.",
4
- "version": "0.6.4",
4
+ "version": "0.6.5",
5
5
  "skills": [
6
6
  {
7
7
  "name": "mindlore-ingest",
@@ -44,21 +44,6 @@ Mindlore uses a single global directory:
44
44
  - Files MUST live in the directory matching their `type`
45
45
  - The health check script validates this cross-reference
46
46
 
47
- ### Session Storage (v0.5.3)
48
-
49
- ```
50
- raw/sessions/
51
- ├── kastell/ # Proje bazlı CC session dosyaları
52
- ├── mindlore/
53
- ├── Stok-Takip/
54
- └── {project-slug}/ # cc-session-sync.ts tarafından yazılır
55
- ```
56
-
57
- Session dosyaları `cc-session-sync.ts` tarafından `~/.claude/projects/*/` altından taranır,
58
- `projectSlug()` ile temiz isme dönüştürülür (ör. `C--Users-Omrfc-Documents-kastell` → `kastell`),
59
- ve `raw/sessions/{slug}/{date}-{shortId}.md` olarak yazılır.
60
- Frontmatter: `type: raw, project: {slug}, category: cc-session`
61
-
62
47
  ## 3. Frontmatter
63
48
 
64
49
  Every `.md` file in `.mindlore/` MUST have YAML frontmatter. Format:
@@ -105,7 +90,7 @@ tags: [tag1, tag2]
105
90
  - `raw_slug`: slug of the raw/ file this source was processed from (source→raw traceability)
106
91
  - `status`: `stub` | `active` | `archived` (domain maturity indicator)
107
92
 
108
- ## 4. Ten Operations
93
+ ## 4. Seven Operations
109
94
 
110
95
  ### 4.1 Ingest (skill: /mindlore-ingest)
111
96
 
@@ -116,7 +101,7 @@ Add new knowledge. Flow: capture → raw/ → process → sources/ → update do
116
101
  - PDF mode: CC Read tool (max 20 pages/request) → raw/ → summarize → sources/
117
102
  - **markitdown is NOT used for PDF** — quality is poor. Use CC Read tool or Marker/Chandra (v0.3+)
118
103
 
119
- ### 4.2 Query (skill: /mindlore-query)IMPLEMENTED (v0.2)
104
+ ### 4.2 Query (skill: /mindlore-query, v0.2 PLANNED, not yet implemented)
120
105
 
121
106
  Search and retrieve knowledge. Four modes:
122
107
  - `search`: FTS5 keyword search, return top 3 matches with snippets
@@ -134,7 +119,7 @@ Run 16-point structural check:
134
119
  - Orphan file detection (files not in FTS5)
135
120
  - Frontmatter validation (type-directory cross-reference)
136
121
 
137
- ### 4.4 Log (skill: /mindlore-log)IMPLEMENTED (v0.2)
122
+ ### 4.4 Log (skill: /mindlore-log, v0.2 PLANNED, not yet implemented)
138
123
 
139
124
  Session logging with four modes:
140
125
  - `log`: Write session/task record to diary/
@@ -142,44 +127,33 @@ Session logging with four modes:
142
127
  - `status`: Recent N sessions summary, trends, open items
143
128
  - `save`: Structured delta + log.md append + wiki update
144
129
 
145
- ### 4.5 Decide (skill: /mindlore-decide)IMPLEMENTED (v0.2)
130
+ ### 4.5 Decide (skill: /mindlore-decide, v0.2 PLANNED, not yet implemented)
146
131
 
147
132
  Record decisions with context, options considered, rationale, and outcome.
148
133
  Supports `supersedes` chain for decision evolution.
149
134
 
150
- ### 4.6 Evolve (skill: /mindlore-evolve)IMPLEMENTED (v0.3)
135
+ ### 4.6 Evolve (skill: /mindlore-evolve, v0.3 PLANNED, not yet implemented)
151
136
 
152
137
  Schema co-evolution. Scan domains + sources, suggest structural updates.
153
138
  Run monthly or after major changes.
154
139
 
155
- ### 4.7 Explore (skill: /mindlore-explore)IMPLEMENTED (v0.3)
140
+ ### 4.7 Explore (skill: /mindlore-explore, v0.3 PLANNED, not yet implemented)
156
141
 
157
142
  Discover unexpected connections between sources. Cross-reference analysis.
158
143
 
159
- ### 4.8 Diary (skill: /mindlore-diary) — IMPLEMENTED (v0.5.3)
160
-
161
- Session analysis — decisions, discoveries, frictions, learnings.
162
-
163
- ### 4.9 Reflect (skill: /mindlore-reflect) — IMPLEMENTED (v0.5.3)
164
-
165
- Pattern extraction from episodes, CLAUDE.md update proposals.
166
-
167
- ### 4.10 Maintain (skill: /mindlore-maintain) — IMPLEMENTED (v0.5.3)
168
-
169
- Decay/archive, episode consolidation, contradiction detection.
170
-
171
144
  ## 5. Search Behavior
172
145
 
173
146
  ### FTS5 Search (hooks + scripts)
174
147
 
175
148
  - Database: `.mindlore/mindlore.db`
176
- - Table: `mindlore_fts` (columns: path, content)
177
- - Dedup: `file_hashes` table with SHA256 content-hash
149
+ - Table: `mindlore_fts` — knowledge content (sources, domains, analyses, decisions, diary)
150
+ - Table: `mindlore_fts_sessions` session content (cc-subagent, cc-session) — v0.6.1
151
+ - Dedup: `file_hashes` table with SHA256 content-hash + `table_target` column (v0.6.1)
178
152
  - Tokenizer: `unicode61`
179
153
  - Max results: 3 per query (BM25 ranking)
180
154
  - Hook injects: file path + first 2 headings
181
155
 
182
- ### FTS5 Columns (11-col schema, v0.5.9)
156
+ ### FTS5 Columns (11-col schema, v0.3.3)
183
157
 
184
158
  | Column | Indexed | Source |
185
159
  |--------|---------|--------|
@@ -316,75 +290,3 @@ tags: [testing, jest, mock]
316
290
  - Stats line: "N source, N analysis, N total"
317
291
  - Last 5 added (initially empty)
318
292
  - NO full file listing — discovery via FTS5
319
-
320
- ## 10. Database Tables
321
-
322
- ### mindlore_fts (FTS5 virtual table)
323
-
324
- 11 kolon: path (UNINDEXED), slug, description, type (UNINDEXED), category, title, content, tags, quality (UNINDEXED), date_captured (UNINDEXED), project (UNINDEXED)
325
-
326
- Tokenizer: `porter unicode61`
327
-
328
- ### file_hashes
329
-
330
- Dedup tablosu — content-hash ile aynı dosyanın tekrar indexlenmesini engeller.
331
-
332
- | Kolon | Tip | Açıklama |
333
- |-------|-----|----------|
334
- | path | TEXT PK | Dosya tam yolu |
335
- | content_hash | TEXT | SHA256 hash |
336
- | last_indexed | TEXT | Son index zamanı |
337
- | created_at | TEXT | İlk index zamanı |
338
- | updated_at | TEXT | Son güncelleme zamanı |
339
- | source_type | TEXT | Kaynak tipi (cc-session, cc-subagent, vb.) |
340
- | project_scope | TEXT | Proje adı |
341
- | recall_count | INTEGER | Kaç kez recall edildi |
342
- | last_recalled_at | TEXT | Son recall zamanı |
343
- | archived_at | TEXT | Arşivlenme zamanı (null = aktif) |
344
- | importance | REAL | Kalite→önem dönüşümü (0.0–1.0) |
345
-
346
- > v0.6.0: `QUALITY_HEURISTICS` artık `cc-session`/`cc-subagent` source_type'larını tanıyor (önce eksikti).
347
-
348
- ### episodes
349
-
350
- Session ve bilgi olayları — decision, discovery, friction, learning, reflection.
351
-
352
- | Kolon | Tip | Açıklama |
353
- |-------|-----|----------|
354
- | id | TEXT PK | `ep-{kind}-{timestamp}-{random}` |
355
- | kind | TEXT | decision, discovery, friction, learning, reflection, correction |
356
- | scope | TEXT | session, cross-session, global |
357
- | project | TEXT | Proje adı |
358
- | summary | TEXT | Tek satır özet |
359
- | body | TEXT | Detaylı içerik |
360
- | tags | TEXT | Virgülle ayrılmış etiketler |
361
- | entities | TEXT | İlgili entity'ler |
362
- | parent_id | TEXT | Üst episode referansı |
363
- | status | TEXT | active, archived |
364
- | supersedes | TEXT | Geçersiz kıldığı episode ID |
365
- | source | TEXT | Kaynak (session ID, hook adı) |
366
- | created_at | TEXT | Oluşturulma zamanı |
367
- | consolidation_status | TEXT | raw, consolidated |
368
- | consolidated_into | TEXT | Konsolide edildiği episode ID |
369
- | decay_score | REAL | 0.0–1.0 (1.0 = taze) |
370
- | last_decay_calc | TEXT | Son decay hesaplama zamanı |
371
-
372
- ### skill_memory
373
-
374
- Skill'lerin kalıcı belleği — fork'lar arası veri paylaşımı.
375
-
376
- | Kolon | Tip | Açıklama |
377
- |-------|-----|----------|
378
- | key | TEXT PK | Skill + anahtar adı |
379
- | value | TEXT | JSON veya düz metin |
380
- | updated_at | TEXT | Son güncelleme |
381
-
382
- ## 11. Agents
383
-
384
- 3 agent tanımlı (`agents/` dizini). Model routing `model-router` hook'u tarafından yapılır.
385
-
386
- | Agent | Model | Görev |
387
- |-------|-------|-------|
388
- | mindlore-assistant | sonnet | Genel KB asistanı — query, ingest yönlendirme |
389
- | mindlore-researcher | sonnet | Araştırma — web fetch, kaynak analizi |
390
- | mindlore-librarian | haiku | Organizasyon — tag, kategori, duplicate tespiti |
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.6.4",
2
+ "version": "0.6.5",
3
3
  "models": {
4
4
  "ingest": "haiku",
5
5
  "evolve": "sonnet",
@@ -1,62 +0,0 @@
1
- /** @deprecated Use search-engine.ts + rrf.ts instead. Kept for backward compat until Faz 3. */
2
- import type BetterSqlite3 from 'better-sqlite3';
3
- type Database = BetterSqlite3.Database;
4
- export interface FtsResult {
5
- slug: string;
6
- rank: number;
7
- path?: string;
8
- description?: string;
9
- title?: string;
10
- category?: string;
11
- tags?: string;
12
- }
13
- export interface VecResult {
14
- slug: string;
15
- distance: number;
16
- }
17
- export interface FusedResult {
18
- slug: string;
19
- score: number;
20
- ftsRank?: number;
21
- vecDistance?: number;
22
- path?: string;
23
- description?: string;
24
- title?: string;
25
- category?: string;
26
- tags?: string;
27
- }
28
- export interface RRFOptions {
29
- k?: number;
30
- ftsWeight?: number;
31
- vecWeight?: number;
32
- }
33
- export interface HybridSearchOptions {
34
- maxResults?: number;
35
- k?: number;
36
- ftsWeight?: number;
37
- vecWeight?: number;
38
- synonyms?: Record<string, string[]>;
39
- project?: string;
40
- queryEmbedding?: number[];
41
- }
42
- export declare function getCategoryWeight(category: string): number;
43
- /**
44
- * Convert L2 distance to cosine similarity.
45
- * For normalized vectors: cosine_sim = 1.0 - (l2_dist² / 2.0)
46
- */
47
- export declare function l2ToCosine(l2Distance: number): number;
48
- /**
49
- * Normalize FTS5 BM25 rank to 0-1 range.
50
- * FTS5 returns negative rank — more negative = better match.
51
- */
52
- export declare function normalizeBM25(rank: number): number;
53
- export declare function computeRRF(ftsResults: FtsResult[], vecResults: VecResult[], options?: RRFOptions): FusedResult[];
54
- export declare function searchFts5(db: Database, query: string, limit?: number, project?: string): FtsResult[];
55
- export declare function searchVec(db: Database, queryEmbedding: number[], limit?: number): VecResult[];
56
- /**
57
- * Main hybrid search entry point.
58
- * Falls back to pure FTS5 when vec table or embedding is not available.
59
- */
60
- export declare function hybridSearch(db: Database, query: string, options?: HybridSearchOptions): FusedResult[];
61
- export {};
62
- //# sourceMappingURL=hybrid-search.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../../../scripts/lib/hybrid-search.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAIhD,KAAK,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAcD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAID;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGrD;AAKD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAID,wBAAgB,UAAU,CACxB,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,GAAE,UAAe,GACvB,WAAW,EAAE,CAsDf;AAID,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAW,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,SAAS,EAAE,CA8Bb;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,QAAQ,EACZ,cAAc,EAAE,MAAM,EAAE,EACxB,KAAK,GAAE,MAAW,GACjB,SAAS,EAAE,CAeb;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,WAAW,EAAE,CAoCf"}