mindlore 0.6.0 → 0.6.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 (127) hide show
  1. package/README.md +20 -13
  2. package/SCHEMA.md +3 -2
  3. package/dist/scripts/cc-session-sync.d.ts +1 -0
  4. package/dist/scripts/cc-session-sync.d.ts.map +1 -1
  5. package/dist/scripts/cc-session-sync.js +55 -0
  6. package/dist/scripts/cc-session-sync.js.map +1 -1
  7. package/dist/scripts/fetch-raw.js +62 -2
  8. package/dist/scripts/fetch-raw.js.map +1 -1
  9. package/dist/scripts/init.js +92 -47
  10. package/dist/scripts/init.js.map +1 -1
  11. package/dist/scripts/lib/constants.d.ts +4 -0
  12. package/dist/scripts/lib/constants.d.ts.map +1 -1
  13. package/dist/scripts/lib/constants.js +11 -1
  14. package/dist/scripts/lib/constants.js.map +1 -1
  15. package/dist/scripts/lib/daemon.d.ts +1 -0
  16. package/dist/scripts/lib/daemon.d.ts.map +1 -1
  17. package/dist/scripts/lib/daemon.js +1 -0
  18. package/dist/scripts/lib/daemon.js.map +1 -1
  19. package/dist/scripts/lib/decay.d.ts.map +1 -1
  20. package/dist/scripts/lib/decay.js +3 -0
  21. package/dist/scripts/lib/decay.js.map +1 -1
  22. package/dist/scripts/lib/episodes.d.ts +1 -1
  23. package/dist/scripts/lib/episodes.d.ts.map +1 -1
  24. package/dist/scripts/lib/episodes.js +1 -1
  25. package/dist/scripts/lib/episodes.js.map +1 -1
  26. package/dist/scripts/lib/hybrid-search.d.ts +1 -0
  27. package/dist/scripts/lib/hybrid-search.d.ts.map +1 -1
  28. package/dist/scripts/lib/hybrid-search.js +16 -1
  29. package/dist/scripts/lib/hybrid-search.js.map +1 -1
  30. package/dist/scripts/lib/migrations-v061.d.ts +3 -0
  31. package/dist/scripts/lib/migrations-v061.d.ts.map +1 -0
  32. package/dist/scripts/lib/migrations-v061.js +58 -0
  33. package/dist/scripts/lib/migrations-v061.js.map +1 -0
  34. package/dist/scripts/lib/migrations-v062.d.ts +3 -0
  35. package/dist/scripts/lib/migrations-v062.d.ts.map +1 -0
  36. package/dist/scripts/lib/migrations-v062.js +35 -0
  37. package/dist/scripts/lib/migrations-v062.js.map +1 -0
  38. package/dist/scripts/lib/session-payload.d.ts.map +1 -1
  39. package/dist/scripts/lib/session-payload.js +12 -0
  40. package/dist/scripts/lib/session-payload.js.map +1 -1
  41. package/dist/scripts/lib/triage.d.ts +18 -0
  42. package/dist/scripts/lib/triage.d.ts.map +1 -0
  43. package/dist/scripts/lib/triage.js +81 -0
  44. package/dist/scripts/lib/triage.js.map +1 -0
  45. package/dist/scripts/mindlore-daemon.js +1 -0
  46. package/dist/scripts/mindlore-daemon.js.map +1 -1
  47. package/dist/scripts/mindlore-doctor.d.ts +18 -0
  48. package/dist/scripts/mindlore-doctor.d.ts.map +1 -0
  49. package/dist/scripts/mindlore-doctor.js +243 -0
  50. package/dist/scripts/mindlore-doctor.js.map +1 -0
  51. package/dist/scripts/mindlore-fts5-index.js +16 -3
  52. package/dist/scripts/mindlore-fts5-index.js.map +1 -1
  53. package/dist/scripts/mindlore-fts5-search.js +12 -10
  54. package/dist/scripts/mindlore-fts5-search.js.map +1 -1
  55. package/dist/scripts/mindlore-health-check.d.ts +10 -0
  56. package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
  57. package/dist/scripts/mindlore-health-check.js +26 -1
  58. package/dist/scripts/mindlore-health-check.js.map +1 -1
  59. package/dist/scripts/mindlore-perf.d.ts +22 -0
  60. package/dist/scripts/mindlore-perf.d.ts.map +1 -0
  61. package/dist/scripts/mindlore-perf.js +130 -0
  62. package/dist/scripts/mindlore-perf.js.map +1 -0
  63. package/dist/tests/compaction-snapshot.test.d.ts +2 -0
  64. package/dist/tests/compaction-snapshot.test.d.ts.map +1 -0
  65. package/dist/tests/compaction-snapshot.test.js +55 -0
  66. package/dist/tests/compaction-snapshot.test.js.map +1 -0
  67. package/dist/tests/decay.test.js +29 -0
  68. package/dist/tests/decay.test.js.map +1 -1
  69. package/dist/tests/diary.test.js +3 -3
  70. package/dist/tests/diary.test.js.map +1 -1
  71. package/dist/tests/doctor.test.d.ts +2 -0
  72. package/dist/tests/doctor.test.d.ts.map +1 -0
  73. package/dist/tests/doctor.test.js +82 -0
  74. package/dist/tests/doctor.test.js.map +1 -0
  75. package/dist/tests/fetch-raw.test.js +12 -5
  76. package/dist/tests/fetch-raw.test.js.map +1 -1
  77. package/dist/tests/fts5.test.js +28 -0
  78. package/dist/tests/fts5.test.js.map +1 -1
  79. package/dist/tests/health-check-memory.test.js +27 -0
  80. package/dist/tests/health-check-memory.test.js.map +1 -1
  81. package/dist/tests/helpers/db.d.ts.map +1 -1
  82. package/dist/tests/helpers/db.js +3 -1
  83. package/dist/tests/helpers/db.js.map +1 -1
  84. package/dist/tests/hook-smoke.test.js +27 -0
  85. package/dist/tests/hook-smoke.test.js.map +1 -1
  86. package/dist/tests/hybrid-search.test.js +25 -0
  87. package/dist/tests/hybrid-search.test.js.map +1 -1
  88. package/dist/tests/init.test.js +20 -0
  89. package/dist/tests/init.test.js.map +1 -1
  90. package/dist/tests/migrations-v061.test.d.ts +2 -0
  91. package/dist/tests/migrations-v061.test.d.ts.map +1 -0
  92. package/dist/tests/migrations-v061.test.js +70 -0
  93. package/dist/tests/migrations-v061.test.js.map +1 -0
  94. package/dist/tests/migrations-v062.test.d.ts +2 -0
  95. package/dist/tests/migrations-v062.test.d.ts.map +1 -0
  96. package/dist/tests/migrations-v062.test.js +61 -0
  97. package/dist/tests/migrations-v062.test.js.map +1 -0
  98. package/dist/tests/nomination.test.js +1 -1
  99. package/dist/tests/savings.test.d.ts +2 -0
  100. package/dist/tests/savings.test.d.ts.map +1 -0
  101. package/dist/tests/savings.test.js +87 -0
  102. package/dist/tests/savings.test.js.map +1 -0
  103. package/dist/tests/session-focus.test.js +15 -0
  104. package/dist/tests/session-focus.test.js.map +1 -1
  105. package/dist/tests/session-summary.test.d.ts +2 -0
  106. package/dist/tests/session-summary.test.d.ts.map +1 -0
  107. package/dist/tests/session-summary.test.js +102 -0
  108. package/dist/tests/session-summary.test.js.map +1 -0
  109. package/dist/tests/telemetry-perf.test.d.ts +2 -0
  110. package/dist/tests/telemetry-perf.test.d.ts.map +1 -0
  111. package/dist/tests/telemetry-perf.test.js +65 -0
  112. package/dist/tests/telemetry-perf.test.js.map +1 -0
  113. package/dist/tests/triage.test.d.ts +2 -0
  114. package/dist/tests/triage.test.d.ts.map +1 -0
  115. package/dist/tests/triage.test.js +69 -0
  116. package/dist/tests/triage.test.js.map +1 -0
  117. package/hooks/lib/mindlore-common.cjs +54 -6
  118. package/hooks/mindlore-fts5-sync.cjs +10 -4
  119. package/hooks/mindlore-post-compact.cjs +23 -3
  120. package/hooks/mindlore-pre-compact.cjs +78 -3
  121. package/hooks/mindlore-search.cjs +20 -11
  122. package/hooks/mindlore-session-end.cjs +32 -19
  123. package/hooks/mindlore-session-focus.cjs +107 -72
  124. package/package.json +7 -4
  125. package/plugin.json +1 -1
  126. package/skills/mindlore-maintain/SKILL.md +1 -0
  127. package/templates/config.json +1 -1
@@ -10,23 +10,103 @@
10
10
 
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
- const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, isDaemonRunning, getDaemonPidFile, withTelemetry } = require('./lib/mindlore-common.cjs');
13
+ const { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, withTelemetry, withTimeoutDb } = require('./lib/mindlore-common.cjs');
14
+
15
+ function isCorruptionError(err) {
16
+ const code = err?.code ?? '';
17
+ const msg = String(err?.message ?? err);
18
+ return code === 'SQLITE_CORRUPT' || code === 'SQLITE_NOTADB' || /corrupt|malformed/i.test(msg);
19
+ }
20
+
21
+ function recoverCorruptDb(db, dbPath, reason) {
22
+ try { db.close(); } catch { /* already closed */ }
23
+ const bakPath = dbPath + '.corrupt.bak';
24
+ try { fs.copyFileSync(dbPath, bakPath); } catch { /* best effort */ }
25
+ try { fs.unlinkSync(dbPath); } catch { /* best effort */ }
26
+ hookLog('session-focus', 'warn', reason);
27
+ }
28
+
29
+ function tryOpenDb(dbPath) {
30
+ return openDatabase(dbPath, { readonly: true });
31
+ }
32
+
33
+ function loadDbContent(db, baseDir, config, output, timings) {
34
+ // Session payload: Session summary, Decisions, Friction, Learnings
35
+ const tPayload = Date.now();
36
+ try {
37
+ const { buildSessionPayload } = require('../dist/scripts/lib/session-payload.js');
38
+ const project = path.basename(process.cwd());
39
+ const payloadBudget = config?.tokenBudget?.sessionInject ?? 2000;
40
+ const payload = buildSessionPayload(db, baseDir, project, payloadBudget);
41
+ if (!payload.skipInjection) {
42
+ for (const section of payload.sections) {
43
+ output.push(`[Mindlore ${section.label}]\n${section.content}`);
44
+ }
45
+ }
46
+ } catch (_payloadErr) {
47
+ // Session payload is optional — don't break session start
48
+ }
49
+ timings.db_payload = Date.now() - tPayload;
50
+
51
+ // Supersedes chain display
52
+ const tSuperseded = Date.now();
53
+ if (hasEpisodesTable(db)) {
54
+ const project = path.basename(process.cwd());
55
+
56
+ const chains = querySupersededChains(db, { project, days: 7, limit: 5 });
57
+ if (chains.length > 0) {
58
+ output.push(`[Mindlore Supersedes]\n${formatSupersededChains(chains)}`);
59
+ }
60
+
61
+ // Episode consolidation reminder
62
+ try {
63
+ const rawCount = withTimeoutDb(db,
64
+ "SELECT COUNT(*) as cnt FROM episodes WHERE consolidation_status = 'raw' OR consolidation_status IS NULL",
65
+ [], { mode: 'get' });
66
+ const cnt = rawCount?.cnt ?? 0;
67
+ const consolThreshold = config?.consolidation?.threshold ?? 50;
68
+ if (cnt >= consolThreshold) {
69
+ output.push(`[Mindlore] ${cnt} raw episode birikti — \`/mindlore-maintain consolidate\` ile birleştirmeyi düşün.`);
70
+ }
71
+ } catch (_err) { /* consolidation_status column may not exist yet */ }
72
+ }
73
+ timings.db_episodes = Date.now() - tSuperseded;
74
+
75
+ // Stale content check
76
+ const tStale = Date.now();
77
+ try {
78
+ const thirtyDaysAgo = new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)).toISOString();
79
+ const row = withTimeoutDb(db, 'SELECT COUNT(*) as cnt FROM file_hashes WHERE last_indexed < ?', [thirtyDaysAgo], { mode: 'get' });
80
+ const staleCount = row?.cnt ?? 0;
81
+ if (staleCount > 3) {
82
+ output.push(`[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis — \`/mindlore-evolve\` dusun]`);
83
+ }
84
+ } catch (_staleErr) { /* file_hashes may not exist */ }
85
+ timings.db_stale = Date.now() - tStale;
86
+ }
14
87
 
15
88
  function main() {
89
+ const t0 = Date.now();
16
90
  const baseDir = findMindloreDir();
17
91
  if (!baseDir) return; // No .mindlore/ found, silently skip
18
92
 
19
93
  const output = [];
20
94
  const config = readConfig(baseDir);
95
+ const timings = {};
96
+ let sourceChars = 0;
21
97
 
22
98
  // Inject INDEX.md
99
+ const tIndex = Date.now();
23
100
  const indexPath = path.join(baseDir, 'INDEX.md');
24
101
  if (fs.existsSync(indexPath)) {
102
+ sourceChars += fs.statSync(indexPath).size;
25
103
  const content = fs.readFileSync(indexPath, 'utf8').trim();
26
104
  output.push(`[Mindlore INDEX]\n${content}`);
27
105
  }
106
+ timings.index_read = Date.now() - tIndex;
28
107
 
29
108
  // Inject latest delta + reflect trigger (single readdirSync)
109
+ const tDiary = Date.now();
30
110
  const diaryDir = path.join(baseDir, 'diary');
31
111
  if (fs.existsSync(diaryDir)) {
32
112
  try {
@@ -36,6 +116,7 @@ function main() {
36
116
  const sorted = [...diaryFiles].sort();
37
117
  const latestName = sorted[sorted.length - 1];
38
118
  const latestPath = path.join(diaryDir, latestName);
119
+ sourceChars += fs.statSync(latestPath).size;
39
120
  const deltaContent = fs.readFileSync(latestPath, 'utf8').trim();
40
121
  const { meta } = parseFrontmatter(deltaContent);
41
122
  const deltaProject = meta.project || null;
@@ -52,8 +133,10 @@ function main() {
52
133
  }
53
134
  } catch (_err) { /* skip */ }
54
135
  }
136
+ timings.diary_walk = Date.now() - tDiary;
55
137
 
56
138
  // Version check: compare .version (installed) vs .pkg-version (package)
139
+ const tVersion = Date.now();
57
140
  // Both are flat strings written by init — no JSON parse needed on session start
58
141
  const versionPath = path.join(baseDir, '.version');
59
142
  const pkgVersionPath = path.join(baseDir, '.pkg-version');
@@ -66,66 +149,36 @@ function main() {
66
149
  }
67
150
  }
68
151
  } catch (_err) { /* skip */ }
152
+ timings.version_check = Date.now() - tVersion;
69
153
 
70
154
  // v0.5.4: Consolidated session payload (replaces scattered episodes/activity/alerts injection)
155
+ const tDb = Date.now();
156
+ const outputLenBeforeDb = output.reduce((s, o) => s + o.length, 0);
71
157
  try {
72
158
  const dbPath = path.join(baseDir, 'mindlore.db');
73
- const db = openDatabase(dbPath, { readonly: true });
159
+ const tDbOpen = Date.now();
160
+ const db = tryOpenDb(dbPath);
161
+ timings.db_open = Date.now() - tDbOpen;
162
+ timings.db_integrity = 0;
163
+
74
164
  if (db) {
75
165
  try {
76
- // Session payload: Session summary, Decisions, Friction, Learnings
77
- try {
78
- const { buildSessionPayload } = require('../dist/scripts/lib/session-payload.js');
79
- const project = path.basename(process.cwd());
80
- const payloadBudget = config?.tokenBudget?.sessionInject ?? 2000;
81
- const payload = buildSessionPayload(db, baseDir, project, payloadBudget);
82
- if (!payload.skipInjection) {
83
- for (const section of payload.sections) {
84
- output.push(`[Mindlore ${section.label}]\n${section.content}`);
85
- }
86
- }
87
- } catch (_payloadErr) {
88
- // Session payload is optional — don't break session start
89
- }
90
-
91
- // v0.4.1: Supersedes chain display (kept — not covered by session-payload)
92
- if (hasEpisodesTable(db)) {
93
- const project = path.basename(process.cwd());
94
-
95
- const chains = querySupersededChains(db, { project, days: 7, limit: 5 });
96
- if (chains.length > 0) {
97
- output.push(`[Mindlore Supersedes]\n${formatSupersededChains(chains)}`);
98
- }
99
-
100
- // v0.5.3: Episode consolidation reminder (kept — threshold-based reminder)
101
- try {
102
- const rawCount = db.prepare(
103
- "SELECT COUNT(*) as cnt FROM episodes WHERE consolidation_status = 'raw' OR consolidation_status IS NULL"
104
- ).get();
105
- const cnt = rawCount?.cnt ?? 0;
106
- const consolThreshold = config?.consolidation?.threshold ?? 50;
107
- if (cnt >= consolThreshold) {
108
- output.push(`[Mindlore] ${cnt} raw episode birikti — \`/mindlore-maintain consolidate\` ile birleştirmeyi düşün.`);
109
- }
110
- } catch (_err) { /* consolidation_status column may not exist yet */ }
166
+ loadDbContent(db, baseDir, config, output, timings);
167
+ } catch (err) {
168
+ if (isCorruptionError(err)) {
169
+ recoverCorruptDb(db, dbPath, `Corrupt DB detected during query: ${err?.message ?? err}`);
111
170
  }
112
-
113
- // v0.5.5: Stale content check (reuses open DB handle)
114
- try {
115
- const thirtyDaysAgo = new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)).toISOString();
116
- const row = db.prepare('SELECT COUNT(*) as cnt FROM file_hashes WHERE last_indexed < ?').get(thirtyDaysAgo);
117
- const staleCount = row?.cnt ?? 0;
118
- if (staleCount > 3) {
119
- output.push(`[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis — \`/mindlore-evolve\` dusun]`);
120
- }
121
- } catch (_staleErr) { /* file_hashes may not exist */ }
122
171
  } finally {
123
- db.close();
172
+ try { db.close(); } catch { /* already closed by recovery */ }
124
173
  }
125
174
  }
126
175
  } catch (_err) { /* graceful skip */ }
176
+ const outputLenAfterDb = output.reduce((s, o) => s + o.length, 0);
177
+ sourceChars += (outputLenAfterDb - outputLenBeforeDb);
178
+ timings.db_total = Date.now() - tDb;
127
179
 
128
- hookLog('session-focus', 'info', 'session started');
180
+ timings.total = Date.now() - t0;
181
+ hookLog('session-focus', 'info', `timings: ${JSON.stringify(timings)}`);
129
182
 
130
183
  // Token budget for session inject
131
184
  // Defaults match DEFAULT_TOKEN_BUDGET in scripts/lib/constants.ts
@@ -137,33 +190,15 @@ function main() {
137
190
  joined = joined.slice(0, maxInjectChars) + '\n[...truncated by token budget]';
138
191
  }
139
192
 
140
- // v0.5.5: Auto-start embedding daemon if not already running
141
- // Skip in test environments to avoid file lock issues
142
- const skipDaemon = process.env.NODE_ENV === 'test' || baseDir.includes('.test-');
143
- if (!skipDaemon) {
144
- try {
145
- const status = isDaemonRunning(getDaemonPidFile());
146
- if (!status.running) {
147
- const daemonScript = path.join(__dirname, '..', 'dist', 'scripts', 'mindlore-daemon.js');
148
- if (fs.existsSync(daemonScript)) {
149
- const { spawn } = require('child_process');
150
- const child = spawn(process.execPath, [daemonScript, 'start'], {
151
- detached: true,
152
- stdio: 'ignore',
153
- windowsHide: true,
154
- });
155
- child.unref();
156
- hookLog('session-focus', 'info', 'Daemon auto-started, pid=' + child.pid);
157
- }
158
- }
159
- } catch (_err) {
160
- hookLog('session-focus', 'warn', 'Daemon auto-start failed: ' + (_err?.message || _err));
161
- }
162
- }
193
+ // v0.6.1: Daemon auto-start removed (daemon deprecated MCP Server in v0.7)
163
194
 
164
195
  if (joined.length > 0) {
165
196
  process.stdout.write(joined + '\n');
166
197
  }
198
+
199
+ const inject_tokens = Math.ceil(joined.length / 4);
200
+ const source_tokens = Math.ceil(sourceChars / 4);
201
+ return { inject_tokens, source_tokens };
167
202
  }
168
203
 
169
204
  withTelemetry('mindlore-session-focus', main).catch(err => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindlore",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "AI-native knowledge system for Claude Code",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -20,7 +20,10 @@
20
20
  "quality": "node dist/scripts/quality-populate.js",
21
21
  "fetch-raw": "node dist/scripts/fetch-raw.js",
22
22
  "cc-sync": "node dist/scripts/cc-memory-bulk-sync.js",
23
- "cleanup": "node dist/scripts/maintain-cleanup.js"
23
+ "cleanup": "node dist/scripts/maintain-cleanup.js",
24
+ "perf": "node dist/scripts/mindlore-perf.js",
25
+ "doctor": "node dist/scripts/mindlore-doctor.js",
26
+ "audit": "npm audit --audit-level=moderate"
24
27
  },
25
28
  "keywords": [
26
29
  "claude-code",
@@ -50,12 +53,12 @@
50
53
  "zod": "^4.3.6"
51
54
  },
52
55
  "devDependencies": {
56
+ "@huggingface/transformers": "^4.2.0",
53
57
  "@types/better-sqlite3": "^7.6.13",
54
58
  "@types/jest": "^30.0.0",
55
59
  "@types/node": "^25.6.0",
56
- "@typescript-eslint/eslint-plugin": "^8.58.1",
60
+ "@typescript-eslint/eslint-plugin": "^8.59.0",
57
61
  "@typescript-eslint/parser": "^8.58.1",
58
- "@huggingface/transformers": "^4.2.0",
59
62
  "eslint": "^10.2.0",
60
63
  "globals": "^17.5.0",
61
64
  "jest": "^30.3.0",
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.0",
4
+ "version": "0.6.2",
5
5
  "skills": [
6
6
  {
7
7
  "name": "mindlore-ingest",
@@ -24,6 +24,7 @@ KB bakım skill'i. Reflect düşünür, maintain temizler.
24
24
  - `/mindlore-maintain decay` — stale doc listesi + archive flow
25
25
  - `/mindlore-maintain consolidate` — episode gruplama + dosyaya promote
26
26
  - `/mindlore-maintain contradictions` — çelişki analizi
27
+ - `/mindlore-maintain triage` — unpromoted raw dosyaları listele + metadata göster
27
28
 
28
29
  ## Decay Mode
29
30
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.6.0",
2
+ "version": "0.6.2",
3
3
  "models": {
4
4
  "ingest": "haiku",
5
5
  "evolve": "sonnet",