mindlore 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
- package/dist/scripts/cc-session-sync.js +2 -2
- package/dist/scripts/cc-session-sync.js.map +1 -1
- package/dist/scripts/fetch-raw.js +17 -8
- package/dist/scripts/fetch-raw.js.map +1 -1
- package/dist/scripts/init.js +42 -24
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/all-migrations.d.ts +6 -0
- package/dist/scripts/lib/all-migrations.d.ts.map +1 -0
- package/dist/scripts/lib/all-migrations.js +32 -0
- package/dist/scripts/lib/all-migrations.js.map +1 -0
- package/dist/scripts/lib/daemon.d.ts.map +1 -1
- package/dist/scripts/lib/daemon.js +3 -0
- package/dist/scripts/lib/daemon.js.map +1 -1
- package/dist/scripts/lib/input-validation.d.ts +5 -0
- package/dist/scripts/lib/input-validation.d.ts.map +1 -0
- package/dist/scripts/lib/input-validation.js +48 -0
- package/dist/scripts/lib/input-validation.js.map +1 -0
- package/dist/scripts/lib/migrations-v066.d.ts +4 -0
- package/dist/scripts/lib/migrations-v066.d.ts.map +1 -0
- package/dist/scripts/lib/migrations-v066.js +14 -0
- package/dist/scripts/lib/migrations-v066.js.map +1 -0
- package/dist/scripts/lib/privacy-filter.d.ts.map +1 -1
- package/dist/scripts/lib/privacy-filter.js +3 -0
- package/dist/scripts/lib/privacy-filter.js.map +1 -1
- package/dist/scripts/lib/rrf.d.ts.map +1 -1
- package/dist/scripts/lib/rrf.js +10 -10
- package/dist/scripts/lib/rrf.js.map +1 -1
- package/dist/scripts/lib/search-cache.d.ts +1 -0
- package/dist/scripts/lib/search-cache.d.ts.map +1 -1
- package/dist/scripts/lib/search-cache.js +6 -0
- package/dist/scripts/lib/search-cache.js.map +1 -1
- package/dist/scripts/lib/search-engine.d.ts +1 -1
- package/dist/scripts/lib/search-engine.d.ts.map +1 -1
- package/dist/scripts/lib/search-engine.js +3 -2
- package/dist/scripts/lib/search-engine.js.map +1 -1
- package/dist/scripts/lib/session-payload.d.ts +1 -1
- package/dist/scripts/lib/session-payload.d.ts.map +1 -1
- package/dist/scripts/lib/session-payload.js +24 -6
- package/dist/scripts/lib/session-payload.js.map +1 -1
- package/dist/scripts/mindlore-daemon.js +1 -3
- package/dist/scripts/mindlore-daemon.js.map +1 -1
- package/dist/scripts/mindlore-fts5-index.js +2 -5
- package/dist/scripts/mindlore-fts5-index.js.map +1 -1
- package/dist/scripts/mindlore-obsidian.js +4 -0
- package/dist/scripts/mindlore-obsidian.js.map +1 -1
- package/dist/tests/episodes-inject.test.js +71 -0
- package/dist/tests/episodes-inject.test.js.map +1 -1
- package/dist/tests/fetch-raw-security.test.d.ts +2 -0
- package/dist/tests/fetch-raw-security.test.d.ts.map +1 -0
- package/dist/tests/fetch-raw-security.test.js +72 -0
- package/dist/tests/fetch-raw-security.test.js.map +1 -0
- package/dist/tests/fetch-raw.test.js +4 -4
- package/dist/tests/fetch-raw.test.js.map +1 -1
- package/dist/tests/fts5.test.js +23 -22
- package/dist/tests/fts5.test.js.map +1 -1
- package/dist/tests/helpers/db.d.ts +1 -0
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +9 -1
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/init.test.js +26 -0
- package/dist/tests/init.test.js.map +1 -1
- package/dist/tests/input-validation.test.d.ts +2 -0
- package/dist/tests/input-validation.test.d.ts.map +1 -0
- package/dist/tests/input-validation.test.js +113 -0
- package/dist/tests/input-validation.test.js.map +1 -0
- package/dist/tests/migrations-v063.test.js +1 -1
- package/dist/tests/migrations-v066.test.d.ts +2 -0
- package/dist/tests/migrations-v066.test.d.ts.map +1 -0
- package/dist/tests/migrations-v066.test.js +54 -0
- package/dist/tests/migrations-v066.test.js.map +1 -0
- package/dist/tests/obsidian.test.js +2 -1
- package/dist/tests/obsidian.test.js.map +1 -1
- package/dist/tests/privacy-filter.test.js +25 -50
- package/dist/tests/privacy-filter.test.js.map +1 -1
- package/dist/tests/search-hook.test.js +0 -44
- package/dist/tests/search-hook.test.js.map +1 -1
- package/dist/tests/sec-regression.test.d.ts +2 -0
- package/dist/tests/sec-regression.test.d.ts.map +1 -0
- package/dist/tests/sec-regression.test.js +174 -0
- package/dist/tests/sec-regression.test.js.map +1 -0
- package/dist/tests/session-focus-helpers.test.d.ts +2 -0
- package/dist/tests/session-focus-helpers.test.d.ts.map +1 -0
- package/dist/tests/session-focus-helpers.test.js +80 -0
- package/dist/tests/session-focus-helpers.test.js.map +1 -0
- package/dist/tests/session-focus.test.js +19 -0
- package/dist/tests/session-focus.test.js.map +1 -1
- package/dist/tests/stats-skill.test.d.ts +2 -0
- package/dist/tests/stats-skill.test.d.ts.map +1 -0
- package/dist/tests/stats-skill.test.js +55 -0
- package/dist/tests/stats-skill.test.js.map +1 -0
- package/dist/tests/stop-words.test.js +26 -0
- package/dist/tests/stop-words.test.js.map +1 -1
- package/hooks/lib/mindlore-common.cjs +23 -4
- package/hooks/mindlore-fts5-sync.cjs +4 -3
- package/hooks/mindlore-index.cjs +6 -7
- package/hooks/mindlore-pre-compact.cjs +5 -4
- package/hooks/mindlore-search.cjs +2 -1
- package/hooks/mindlore-session-end.cjs +10 -10
- package/hooks/mindlore-session-focus.cjs +82 -29
- package/package.json +1 -1
- package/plugin.json +6 -1
- package/skills/mindlore-ingest/SKILL.md +11 -0
- package/skills/mindlore-stats/SKILL.md +106 -0
- package/templates/SCHEMA.md +10 -108
- package/templates/config.json +1 -1
- package/templates/extraction/article.md +15 -0
- package/templates/extraction/changelog.md +15 -0
- package/templates/extraction/default.md +15 -0
- package/templates/extraction/docs.md +15 -0
- package/templates/extraction/github-repo.md +17 -0
- package/dist/scripts/lib/hybrid-search.d.ts +0 -62
- package/dist/scripts/lib/hybrid-search.d.ts.map +0 -1
- package/dist/scripts/lib/hybrid-search.js +0 -171
- package/dist/scripts/lib/hybrid-search.js.map +0 -1
- package/dist/tests/hybrid-search.test.d.ts +0 -2
- package/dist/tests/hybrid-search.test.d.ts.map +0 -1
- package/dist/tests/hybrid-search.test.js +0 -139
- package/dist/tests/hybrid-search.test.js.map +0 -1
- package/dist/tests/index-cli-embed.test.d.ts +0 -7
- package/dist/tests/index-cli-embed.test.d.ts.map +0 -1
- package/dist/tests/index-cli-embed.test.js +0 -128
- package/dist/tests/index-cli-embed.test.js.map +0 -1
- package/dist/tests/search-cli-hybrid.test.d.ts +0 -6
- package/dist/tests/search-cli-hybrid.test.d.ts.map +0 -1
- package/dist/tests/search-cli-hybrid.test.js +0 -103
- package/dist/tests/search-cli-hybrid.test.js.map +0 -1
|
@@ -45,10 +45,11 @@ function collectRecentEpisodes(baseDir) {
|
|
|
45
45
|
|
|
46
46
|
function collectGitDiff() {
|
|
47
47
|
try {
|
|
48
|
-
const {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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) {
|
|
@@ -151,7 +151,8 @@ function main() {
|
|
|
151
151
|
|
|
152
152
|
const headingStr = headings.length > 0 ? `\nBasliklar: ${headings.join(', ')}` : '';
|
|
153
153
|
const tagsStr = r.tags ? `\nTags: ${r.tags}` : '';
|
|
154
|
-
const
|
|
154
|
+
const snippetOrDesc = r.snippet || description;
|
|
155
|
+
const entry = `[Mindlore: ${category}/${title}] ${snippetOrDesc}\nDosya: ${relativePath}${tagsStr}${headingStr}`;
|
|
155
156
|
const truncated = entry.slice(0, perResultChars);
|
|
156
157
|
totalUsed += truncated.length;
|
|
157
158
|
output.push(truncated);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
|
-
const {
|
|
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 =
|
|
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 =
|
|
503
|
+
const status = execFileSync(git, ['status', '--porcelain'], execOpts(5000)).trim();
|
|
504
504
|
if (!status) return; // nothing to commit
|
|
505
505
|
|
|
506
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,18 +12,63 @@ 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 truncateSection(content, sectionRegex, keepCount, label) {
|
|
16
|
+
const match = content.match(sectionRegex);
|
|
17
|
+
if (!match) return content;
|
|
18
|
+
const lines = match[2].trim().split('\n');
|
|
19
|
+
if (lines.length <= keepCount) return content;
|
|
20
|
+
const kept = lines.slice(0, keepCount).join('\n');
|
|
21
|
+
return content.replace(match[2].trim(), kept + `\n- ...ve ${lines.length - keepCount} ${label} daha`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function truncateCommits(content) {
|
|
25
|
+
return truncateSection(content, /(## Commits\n)((?:- [^\n]+\n?)+)/, 5, 'commit');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function truncateChangedFiles(content) {
|
|
29
|
+
return truncateSection(content, /(## Changed Files\n)((?:- [^\n]+\n?)+)/, 10, 'dosya');
|
|
30
|
+
}
|
|
31
|
+
|
|
15
32
|
function tryOpenDb(dbPath) {
|
|
16
33
|
return openDatabase(dbPath, { readonly: true });
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
function
|
|
36
|
+
function getEpisodeStats(db, config, project) {
|
|
37
|
+
const chains = querySupersededChains(db, { project, days: 7, limit: 5 });
|
|
38
|
+
let consolidationMsg = null;
|
|
39
|
+
try {
|
|
40
|
+
const rawCount = withTimeoutDb(db,
|
|
41
|
+
"SELECT COUNT(*) as cnt FROM episodes WHERE consolidation_status = 'raw' OR consolidation_status IS NULL",
|
|
42
|
+
[], { mode: 'get' });
|
|
43
|
+
const cnt = rawCount?.cnt ?? 0;
|
|
44
|
+
const consolThreshold = config?.consolidation?.threshold ?? 50;
|
|
45
|
+
if (cnt >= consolThreshold) {
|
|
46
|
+
consolidationMsg = `[Mindlore] ${cnt} raw episode birikti — \`/mindlore-maintain consolidate\` ile birleştirmeyi düşün.`;
|
|
47
|
+
}
|
|
48
|
+
} catch (_err) { /* consolidation_status column may not exist yet */ }
|
|
49
|
+
return { chains, consolidationMsg };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function checkStaleContent(db) {
|
|
53
|
+
try {
|
|
54
|
+
const thirtyDaysAgo = new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)).toISOString();
|
|
55
|
+
const row = withTimeoutDb(db, 'SELECT COUNT(*) as cnt FROM file_hashes WHERE last_indexed < ?', [thirtyDaysAgo], { mode: 'get' });
|
|
56
|
+
const staleCount = row?.cnt ?? 0;
|
|
57
|
+
if (staleCount > 3) {
|
|
58
|
+
return `[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis — \`/mindlore-evolve\` dusun]`;
|
|
59
|
+
}
|
|
60
|
+
} catch (_staleErr) { /* file_hashes may not exist */ }
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function loadDbContent(db, baseDir, config, output, timings, latestDeltaContent, sessionId) {
|
|
65
|
+
const project = path.basename(process.cwd());
|
|
20
66
|
// Session payload: Session summary, Decisions, Friction, Learnings
|
|
21
67
|
const tPayload = Date.now();
|
|
22
68
|
try {
|
|
23
69
|
const { buildSessionPayload } = require('../dist/scripts/lib/session-payload.js');
|
|
24
|
-
const project = path.basename(process.cwd());
|
|
25
70
|
const payloadBudget = config?.tokenBudget?.sessionInject ?? 2000;
|
|
26
|
-
const payload = buildSessionPayload(db, baseDir, project, payloadBudget, latestDeltaContent);
|
|
71
|
+
const payload = buildSessionPayload(db, baseDir, project, payloadBudget, latestDeltaContent, sessionId);
|
|
27
72
|
for (const section of payload.sections) {
|
|
28
73
|
output.push(`[Mindlore ${section.label}]\n${section.content}`);
|
|
29
74
|
}
|
|
@@ -32,40 +77,25 @@ function loadDbContent(db, baseDir, config, output, timings, latestDeltaContent)
|
|
|
32
77
|
}
|
|
33
78
|
timings.db_payload = Date.now() - tPayload;
|
|
34
79
|
|
|
35
|
-
// Supersedes chain display
|
|
80
|
+
// Supersedes chain display + episode consolidation reminder
|
|
36
81
|
const tSuperseded = Date.now();
|
|
37
82
|
if (hasEpisodesTable(db)) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const chains = querySupersededChains(db, { project, days: 7, limit: 5 });
|
|
83
|
+
const { chains, consolidationMsg } = getEpisodeStats(db, config, project);
|
|
41
84
|
if (chains.length > 0) {
|
|
42
85
|
output.push(`[Mindlore Supersedes]\n${formatSupersededChains(chains)}`);
|
|
43
86
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const rawCount = withTimeoutDb(db,
|
|
48
|
-
"SELECT COUNT(*) as cnt FROM episodes WHERE consolidation_status = 'raw' OR consolidation_status IS NULL",
|
|
49
|
-
[], { mode: 'get' });
|
|
50
|
-
const cnt = rawCount?.cnt ?? 0;
|
|
51
|
-
const consolThreshold = config?.consolidation?.threshold ?? 50;
|
|
52
|
-
if (cnt >= consolThreshold) {
|
|
53
|
-
output.push(`[Mindlore] ${cnt} raw episode birikti — \`/mindlore-maintain consolidate\` ile birleştirmeyi düşün.`);
|
|
54
|
-
}
|
|
55
|
-
} catch (_err) { /* consolidation_status column may not exist yet */ }
|
|
87
|
+
if (consolidationMsg) {
|
|
88
|
+
output.push(consolidationMsg);
|
|
89
|
+
}
|
|
56
90
|
}
|
|
57
91
|
timings.db_episodes = Date.now() - tSuperseded;
|
|
58
92
|
|
|
59
93
|
// Stale content check
|
|
60
94
|
const tStale = Date.now();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (staleCount > 3) {
|
|
66
|
-
output.push(`[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis — \`/mindlore-evolve\` dusun]`);
|
|
67
|
-
}
|
|
68
|
-
} catch (_staleErr) { /* file_hashes may not exist */ }
|
|
95
|
+
const staleMsg = checkStaleContent(db);
|
|
96
|
+
if (staleMsg) {
|
|
97
|
+
output.push(staleMsg);
|
|
98
|
+
}
|
|
69
99
|
timings.db_stale = Date.now() - tStale;
|
|
70
100
|
}
|
|
71
101
|
|
|
@@ -74,6 +104,13 @@ function main() {
|
|
|
74
104
|
const baseDir = findMindloreDir();
|
|
75
105
|
if (!baseDir) return; // No .mindlore/ found, silently skip
|
|
76
106
|
|
|
107
|
+
// Read session_id from stdin (Claude Code passes { session_id } to SessionStart hooks)
|
|
108
|
+
let sessionId;
|
|
109
|
+
try {
|
|
110
|
+
const stdinData = JSON.parse(fs.readFileSync(0, 'utf8') || '{}');
|
|
111
|
+
sessionId = stdinData.session_id || undefined;
|
|
112
|
+
} catch { sessionId = undefined; }
|
|
113
|
+
|
|
77
114
|
const output = [];
|
|
78
115
|
const config = readConfig(baseDir);
|
|
79
116
|
const timings = {};
|
|
@@ -107,7 +144,7 @@ function main() {
|
|
|
107
144
|
const deltaProject = meta.project || null;
|
|
108
145
|
const currentProject = getProjectName();
|
|
109
146
|
if (!deltaProject || deltaProject.toLowerCase() === currentProject.toLowerCase()) {
|
|
110
|
-
output.push(`[Mindlore Delta: ${latestName}]\n${deltaContent}`);
|
|
147
|
+
output.push(`[Mindlore Delta: ${latestName}]\n${truncateChangedFiles(truncateCommits(deltaContent))}`);
|
|
111
148
|
}
|
|
112
149
|
}
|
|
113
150
|
|
|
@@ -148,7 +185,19 @@ function main() {
|
|
|
148
185
|
|
|
149
186
|
if (db) {
|
|
150
187
|
try {
|
|
151
|
-
|
|
188
|
+
// Schema version check: warn if DB is behind expected version
|
|
189
|
+
const tSchema = Date.now();
|
|
190
|
+
try {
|
|
191
|
+
const { EXPECTED_SCHEMA_VERSION } = require('../dist/scripts/lib/all-migrations.js');
|
|
192
|
+
const row = db.prepare('SELECT MAX(version) as v FROM schema_versions').get();
|
|
193
|
+
const current = row?.v ?? 0;
|
|
194
|
+
if (current < EXPECTED_SCHEMA_VERSION) {
|
|
195
|
+
output.push(`[Mindlore: schema güncel değil (v${current} → v${EXPECTED_SCHEMA_VERSION}). \`npx mindlore upgrade\` çalıştır.]`);
|
|
196
|
+
}
|
|
197
|
+
} catch (_schemaErr) { /* schema_versions may not exist yet */ }
|
|
198
|
+
timings.schema_check = Date.now() - tSchema;
|
|
199
|
+
|
|
200
|
+
loadDbContent(db, baseDir, config, output, timings, latestDeltaContent, sessionId);
|
|
152
201
|
} catch (err) {
|
|
153
202
|
if (isCorruptionError(err)) {
|
|
154
203
|
recoverCorruptDb(db, dbPath, 'session-focus');
|
|
@@ -190,3 +239,7 @@ withTelemetry('mindlore-session-focus', main).catch(err => {
|
|
|
190
239
|
hookLog('mindlore-session-focus', 'error', err?.message ?? String(err));
|
|
191
240
|
process.exit(0);
|
|
192
241
|
});
|
|
242
|
+
|
|
243
|
+
if (typeof module !== 'undefined') {
|
|
244
|
+
module.exports = { truncateCommits, truncateChangedFiles, getEpisodeStats, checkStaleContent };
|
|
245
|
+
}
|
package/package.json
CHANGED
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
|
+
"version": "0.6.6",
|
|
5
5
|
"skills": [
|
|
6
6
|
{
|
|
7
7
|
"name": "mindlore-ingest",
|
|
@@ -52,6 +52,11 @@
|
|
|
52
52
|
"name": "mindlore-maintain",
|
|
53
53
|
"path": "skills/mindlore-maintain/SKILL.md",
|
|
54
54
|
"description": "KB maintenance — decay/archive stale documents, consolidate 50+ episodes into learnings/insights, detect contradictions. Modes: decay (stale doc archive with git snapshot), consolidate (episode→file promotion), contradictions (wiki-lint + semantic), restore (undo archive). Run without flags for full report."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "mindlore-stats",
|
|
58
|
+
"path": "skills/mindlore-stats/SKILL.md",
|
|
59
|
+
"description": "Show context contribution and cost per session — hook calls, durations, DB stats."
|
|
55
60
|
}
|
|
56
61
|
],
|
|
57
62
|
"agents": [
|
|
@@ -135,6 +135,17 @@ Required frontmatter fields include `source_type` — auto-detected:
|
|
|
135
135
|
- `pdf` for PDF Mode
|
|
136
136
|
- `file` for File Mode
|
|
137
137
|
|
|
138
|
+
### Extraction Template
|
|
139
|
+
|
|
140
|
+
After detecting `source_type`, check if a matching extraction template exists:
|
|
141
|
+
|
|
142
|
+
1. Read `~/.mindlore/templates/extraction/{source_type}.md`
|
|
143
|
+
2. If found, follow the "Extraction Instructions" section for source analysis
|
|
144
|
+
3. If not found, Read `~/.mindlore/templates/extraction/default.md` and follow that
|
|
145
|
+
4. User can override with `--type <type>` argument (e.g., `/mindlore-ingest https://example.com --type changelog`)
|
|
146
|
+
|
|
147
|
+
The template guides WHAT to extract from the source. Apply its instructions when writing the source summary in `sources/{slug}.md`.
|
|
148
|
+
|
|
138
149
|
## Quality Assessment
|
|
139
150
|
|
|
140
151
|
Assign quality automatically during ingest using this heuristic:
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mindlore-stats
|
|
3
|
+
description: Show context contribution and cost per session — hook calls, durations, DB stats.
|
|
4
|
+
effort: low
|
|
5
|
+
context: fork
|
|
6
|
+
allowed-tools: [Bash, Read]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Script Resolution
|
|
10
|
+
|
|
11
|
+
Resolve `MINDLORE_DIR` (active knowledge base directory) using:
|
|
12
|
+
1. If project `.mindlore/` exists → use it
|
|
13
|
+
2. Else → use `~/.mindlore/`
|
|
14
|
+
|
|
15
|
+
# /mindlore-stats
|
|
16
|
+
|
|
17
|
+
Show context contribution and cost per session — hook calls, durations, DB stats.
|
|
18
|
+
|
|
19
|
+
## Trigger
|
|
20
|
+
|
|
21
|
+
User says "mindlore stats", "stats", "context cost", "hook performance", "ne kadar yer kaplıyor".
|
|
22
|
+
|
|
23
|
+
## Execution
|
|
24
|
+
|
|
25
|
+
### 1. Telemetry Analysis
|
|
26
|
+
|
|
27
|
+
Read `$MINDLORE_DIR/telemetry.jsonl` (each line is a JSON object):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Count lines and read last 500 for session estimate
|
|
31
|
+
wc -l "$MINDLORE_DIR/telemetry.jsonl"
|
|
32
|
+
tail -500 "$MINDLORE_DIR/telemetry.jsonl"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Parse each line as JSON with fields: `hook` (string), `duration` (number, ms), `ts` (ISO timestamp), optionally `injectSize` (number, chars).
|
|
36
|
+
|
|
37
|
+
Calculate:
|
|
38
|
+
- **Total hook calls (all time)**: total line count
|
|
39
|
+
- **Hook calls (session)**: lines where `ts` is within last 8 hours
|
|
40
|
+
- **Avg duration per hook**: group by `hook`, compute mean `duration`
|
|
41
|
+
- **Session inject avg**: from events where `hook === "mindlore-session-focus"`, average `injectSize` (chars ÷ 4 ≈ tokens)
|
|
42
|
+
- **Search inject avg**: from events where `hook === "mindlore-search"`, average `injectSize` (chars ÷ 4 ≈ tokens)
|
|
43
|
+
|
|
44
|
+
### 2. DB Stats
|
|
45
|
+
|
|
46
|
+
Query `$MINDLORE_DIR/mindlore.db`:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Indexed docs
|
|
50
|
+
node -e "
|
|
51
|
+
const DB = require('better-sqlite3');
|
|
52
|
+
const db = new DB('$MINDLORE_DIR/mindlore.db', {readonly:true});
|
|
53
|
+
const total = db.prepare('SELECT COUNT(*) as n FROM file_hashes').get().n;
|
|
54
|
+
const stale = db.prepare(\"SELECT COUNT(*) as n FROM file_hashes WHERE last_indexed < datetime('now','-30 days')\").get().n;
|
|
55
|
+
const epRows = db.prepare('SELECT kind, COUNT(*) as n FROM episodes GROUP BY kind').all();
|
|
56
|
+
const sessions = db.prepare('SELECT COUNT(*) as n FROM mindlore_fts_sessions').get()?.n ?? 'N/A';
|
|
57
|
+
console.log(JSON.stringify({total, stale, epRows, sessions}));
|
|
58
|
+
db.close();
|
|
59
|
+
"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Get DB file size:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
node -e "const fs=require('fs'); const s=fs.statSync('$MINDLORE_DIR/mindlore.db'); console.log((s.size/1024/1024).toFixed(2)+' MB');"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. Format Output
|
|
69
|
+
|
|
70
|
+
Print a compact stats table:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
## Mindlore Stats
|
|
74
|
+
|
|
75
|
+
| Metric | Value |
|
|
76
|
+
|--------|-------|
|
|
77
|
+
| DB Size | X MB |
|
|
78
|
+
| Indexed Docs | N |
|
|
79
|
+
| Stale Docs (30d+) | N |
|
|
80
|
+
| Episodes (active) | N |
|
|
81
|
+
| Hook Calls (session) | N |
|
|
82
|
+
| Hook Calls (all time) | N |
|
|
83
|
+
| Avg Hook Duration | Xms |
|
|
84
|
+
| Session Inject Avg | ~N tokens |
|
|
85
|
+
| Search Inject Avg | ~N tokens |
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then add a per-hook breakdown if hook calls > 0:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
### Hook Breakdown (session)
|
|
92
|
+
|
|
93
|
+
| Hook | Calls | Avg Duration |
|
|
94
|
+
|------|-------|-------------|
|
|
95
|
+
| mindlore-session-focus | N | Xms |
|
|
96
|
+
| mindlore-search | N | Xms |
|
|
97
|
+
| ... | | |
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Notes
|
|
101
|
+
|
|
102
|
+
- If `telemetry.jsonl` does not exist: report "No telemetry data yet"
|
|
103
|
+
- If `mindlore.db` does not exist: report "DB not found — run `npx mindlore init`"
|
|
104
|
+
- If `episodes` table missing: skip episode count, show "—"
|
|
105
|
+
- Inject size in tokens is approximate (chars ÷ 4)
|
|
106
|
+
- "Session" = last 8 hours from current time
|
package/templates/SCHEMA.md
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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` (
|
|
177
|
-
-
|
|
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.
|
|
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 |
|
package/templates/config.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
source_type: article
|
|
3
|
+
description: Article/blog post analysis template
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Extraction Instructions
|
|
7
|
+
|
|
8
|
+
Bu source bir makale veya blog yazisidir. Su bilgileri cikar:
|
|
9
|
+
|
|
10
|
+
1. **Tez:** Yazarin ana argumani veya iddiasi (1-2 cumle)
|
|
11
|
+
2. **Destekleyici Argumanlar:** Tezi destekleyen kanit ve ornekler
|
|
12
|
+
3. **Sonuc:** Yazarin vardigi sonuc veya onerisi
|
|
13
|
+
4. **Elestiri:** Zayif noktalar veya eksik perspektifler (varsa)
|
|
14
|
+
|
|
15
|
+
Yazarin uslubunu veya hikaye anlatimini tekrarlama — sadece bilgi ozu.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
source_type: changelog
|
|
3
|
+
description: Changelog/release notes analysis template
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Extraction Instructions
|
|
7
|
+
|
|
8
|
+
Bu source bir changelog veya release notes dosyasidir. Su bilgileri cikar:
|
|
9
|
+
|
|
10
|
+
1. **Breaking Changes:** Geriye uyumsuz degisiklikler ve migration adimlari
|
|
11
|
+
2. **Yeni Ozellikler:** Eklenen ozellikler ve kullanim sekli
|
|
12
|
+
3. **Bug Fix'ler:** Duzeltilen hatalar (sadece onemli olanlar)
|
|
13
|
+
4. **Deprecation:** Kaldirilacak/kaldirilan ozellikler
|
|
14
|
+
|
|
15
|
+
Her maddeyi versiyon numarasiyla iliskilendir. Minor fix'leri atla, sadece etkili degisiklikleri al.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
source_type: default
|
|
3
|
+
description: Generic extraction template (fallback)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Extraction Instructions
|
|
7
|
+
|
|
8
|
+
Bu source icin ozel bir extraction template bulunamadi. Genel ozet cikar:
|
|
9
|
+
|
|
10
|
+
1. **Ozet:** Kaynagin ne hakkinda oldugu (2-3 cumle)
|
|
11
|
+
2. **Temel Bilgiler:** En onemli noktalar ve kavramlar
|
|
12
|
+
3. **Iliskiler:** Diger bilinen konularla baglantilari
|
|
13
|
+
4. **Eyleme Donuk:** Pratikte nasil kullanilabilir
|
|
14
|
+
|
|
15
|
+
Kisa ve oz tut — max 500 kelime.
|