mindlore 0.7.6 → 0.7.7
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +3 -1
- package/dist/scripts/bundle-hooks.js +5 -1
- package/dist/scripts/bundle-hooks.js.map +1 -1
- package/dist/scripts/init.js +49 -10
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +8 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +9 -1
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/db-helpers.d.ts +6 -0
- package/dist/scripts/lib/db-helpers.d.ts.map +1 -1
- package/dist/scripts/lib/db-helpers.js +6 -0
- package/dist/scripts/lib/db-helpers.js.map +1 -1
- package/dist/scripts/lib/read-guard-core.d.ts +21 -0
- package/dist/scripts/lib/read-guard-core.d.ts.map +1 -0
- package/dist/scripts/lib/read-guard-core.js +40 -0
- package/dist/scripts/lib/read-guard-core.js.map +1 -0
- package/dist/scripts/lib/search-cache.d.ts +1 -7
- package/dist/scripts/lib/search-cache.d.ts.map +1 -1
- package/dist/scripts/lib/search-cache.js +3 -25
- package/dist/scripts/lib/search-cache.js.map +1 -1
- package/dist/scripts/lib/search-throttle.d.ts +10 -0
- package/dist/scripts/lib/search-throttle.d.ts.map +1 -0
- package/dist/scripts/lib/search-throttle.js +32 -0
- package/dist/scripts/lib/search-throttle.js.map +1 -0
- package/dist/scripts/lib/settings-cleanup.d.ts.map +1 -1
- package/dist/scripts/lib/settings-cleanup.js +2 -1
- package/dist/scripts/lib/settings-cleanup.js.map +1 -1
- package/dist/scripts/lib/setup-wizard.d.ts +13 -0
- package/dist/scripts/lib/setup-wizard.d.ts.map +1 -0
- package/dist/scripts/lib/setup-wizard.js +51 -0
- package/dist/scripts/lib/setup-wizard.js.map +1 -0
- package/dist/scripts/lib/tool-adapters/decide-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/decide-adapter.js +3 -3
- package/dist/scripts/lib/tool-adapters/decide-adapter.js.map +1 -1
- package/dist/scripts/lib/tool-adapters/get-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/get-adapter.js +10 -2
- package/dist/scripts/lib/tool-adapters/get-adapter.js.map +1 -1
- package/dist/scripts/lib/tool-adapters/ingest-adapter.d.ts.map +1 -1
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js +3 -3
- package/dist/scripts/lib/tool-adapters/ingest-adapter.js.map +1 -1
- package/dist/scripts/lib/transcript-token-estimator.d.ts +8 -0
- package/dist/scripts/lib/transcript-token-estimator.d.ts.map +1 -0
- package/dist/scripts/lib/transcript-token-estimator.js +164 -0
- package/dist/scripts/lib/transcript-token-estimator.js.map +1 -0
- package/dist/scripts/maintain-cleanup.d.ts.map +1 -1
- package/dist/scripts/maintain-cleanup.js +2 -1
- package/dist/scripts/maintain-cleanup.js.map +1 -1
- package/dist/scripts/mcp-server.js +3 -3
- package/dist/scripts/mcp-server.js.map +1 -1
- package/dist/scripts/mindlore-backup.d.ts.map +1 -1
- package/dist/scripts/mindlore-backup.js +3 -2
- package/dist/scripts/mindlore-backup.js.map +1 -1
- package/dist/scripts/mindlore-clean-cache.d.ts +4 -1
- package/dist/scripts/mindlore-clean-cache.d.ts.map +1 -1
- package/dist/scripts/mindlore-clean-cache.js +47 -20
- package/dist/scripts/mindlore-clean-cache.js.map +1 -1
- package/dist/scripts/mindlore-doctor.d.ts +4 -0
- package/dist/scripts/mindlore-doctor.d.ts.map +1 -1
- package/dist/scripts/mindlore-doctor.js +9 -1
- package/dist/scripts/mindlore-doctor.js.map +1 -1
- package/dist/scripts/mindlore-health-check.d.ts +7 -0
- package/dist/scripts/mindlore-health-check.d.ts.map +1 -1
- package/dist/scripts/mindlore-health-check.js +57 -4
- package/dist/scripts/mindlore-health-check.js.map +1 -1
- package/dist/scripts/mindlore-learnings.d.ts +6 -0
- package/dist/scripts/mindlore-learnings.d.ts.map +1 -0
- package/dist/scripts/mindlore-learnings.js +106 -0
- package/dist/scripts/mindlore-learnings.js.map +1 -0
- package/dist/scripts/mindlore-obsidian.js +6 -5
- package/dist/scripts/mindlore-obsidian.js.map +1 -1
- package/dist/scripts/quality-populate.js +2 -1
- package/dist/scripts/quality-populate.js.map +1 -1
- package/dist/scripts/uninstall.js +2 -1
- package/dist/scripts/uninstall.js.map +1 -1
- package/dist/tests/clean-cache-eperm.test.d.ts +2 -0
- package/dist/tests/clean-cache-eperm.test.d.ts.map +1 -0
- package/dist/tests/clean-cache-eperm.test.js +74 -0
- package/dist/tests/clean-cache-eperm.test.js.map +1 -0
- package/dist/tests/doctor.test.js +18 -0
- package/dist/tests/doctor.test.js.map +1 -1
- package/dist/tests/health-check.test.d.ts +2 -0
- package/dist/tests/health-check.test.d.ts.map +1 -0
- package/dist/tests/health-check.test.js +61 -0
- package/dist/tests/health-check.test.js.map +1 -0
- package/dist/tests/helpers/db.d.ts +7 -2
- package/dist/tests/helpers/db.d.ts.map +1 -1
- package/dist/tests/helpers/db.js +16 -14
- package/dist/tests/helpers/db.js.map +1 -1
- package/dist/tests/mindlore-ingest-extraction.test.d.ts +2 -0
- package/dist/tests/mindlore-ingest-extraction.test.d.ts.map +1 -0
- package/dist/tests/mindlore-ingest-extraction.test.js +48 -0
- package/dist/tests/mindlore-ingest-extraction.test.js.map +1 -0
- package/dist/tests/mindlore-learnings.test.d.ts +2 -0
- package/dist/tests/mindlore-learnings.test.d.ts.map +1 -0
- package/dist/tests/mindlore-learnings.test.js +63 -0
- package/dist/tests/mindlore-learnings.test.js.map +1 -0
- package/dist/tests/read-guard-perf.test.d.ts +2 -0
- package/dist/tests/read-guard-perf.test.d.ts.map +1 -0
- package/dist/tests/read-guard-perf.test.js +31 -0
- package/dist/tests/read-guard-perf.test.js.map +1 -0
- package/dist/tests/reflect-trigger.test.js +8 -1
- package/dist/tests/reflect-trigger.test.js.map +1 -1
- package/dist/tests/search-cache.test.js +0 -35
- package/dist/tests/search-cache.test.js.map +1 -1
- package/dist/tests/search-throttle.test.d.ts +2 -0
- package/dist/tests/search-throttle.test.d.ts.map +1 -0
- package/dist/tests/search-throttle.test.js +53 -0
- package/dist/tests/search-throttle.test.js.map +1 -0
- package/dist/tests/session-focus-reflect-nudge.test.js +3 -3
- package/dist/tests/session-focus-reflect-nudge.test.js.map +1 -1
- package/dist/tests/setup-wizard.test.d.ts +2 -0
- package/dist/tests/setup-wizard.test.d.ts.map +1 -0
- package/dist/tests/setup-wizard.test.js +35 -0
- package/dist/tests/setup-wizard.test.js.map +1 -0
- package/dist/tests/transcript-token-estimator.test.d.ts +2 -0
- package/dist/tests/transcript-token-estimator.test.d.ts.map +1 -0
- package/dist/tests/transcript-token-estimator.test.js +122 -0
- package/dist/tests/transcript-token-estimator.test.js.map +1 -0
- package/hooks/cc-memory-bulk-sync.cjs +9 -1
- package/hooks/cc-session-sync.cjs +9 -1
- package/hooks/lib/learnings-loader.cjs +21 -11
- package/hooks/lib/reflect-trigger.cjs +6 -3
- package/hooks/mindlore-cwd-changed.cjs +4 -5
- package/hooks/mindlore-dont-repeat.cjs +2 -1
- package/hooks/mindlore-post-read.cjs +2 -1
- package/hooks/mindlore-pre-compact.cjs +3 -2
- package/hooks/mindlore-read-guard.cjs +62 -35
- package/hooks/mindlore-search.cjs +231 -31
- package/hooks/mindlore-session-end.cjs +6 -8
- package/hooks/mindlore-session-focus.cjs +472 -23
- package/hooks/src/mindlore-cwd-changed.cjs +4 -5
- package/hooks/src/mindlore-dont-repeat.cjs +2 -1
- package/hooks/src/mindlore-post-read.cjs +2 -1
- package/hooks/src/mindlore-pre-compact.cjs +3 -2
- package/hooks/src/mindlore-read-guard.cjs +15 -55
- package/hooks/src/mindlore-search.cjs +39 -10
- package/hooks/src/mindlore-session-end.cjs +6 -8
- package/hooks/src/mindlore-session-focus.cjs +29 -21
- package/mcp-server.cjs +41 -25
- package/package.json +1 -1
- package/plugin.json +6 -1
- package/skills/mindlore-ingest/SKILL.md +21 -0
- package/skills/mindlore-learnings/SKILL.md +30 -0
- package/start.cjs +1 -1
- package/templates/config.json +1 -1
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* mindlore-read-guard — PreToolUse hook (if: "Read")
|
|
6
|
-
*
|
|
7
|
-
* Repeated-read detection: detects files read multiple times
|
|
8
|
-
* in the same session and emits a soft warning.
|
|
9
|
-
* Does NOT block (exit 0) — advisory only.
|
|
10
|
-
*
|
|
11
|
-
* Storage: .mindlore/diary/_session-reads.json
|
|
12
|
-
* Cleanup: session-end hook writes stats to delta then deletes the file.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
4
|
const fs = require('fs');
|
|
16
5
|
const path = require('path');
|
|
17
6
|
const { findMindloreDir, readHookStdin, getProjectName, hookLog, extractSkeleton, withTelemetrySync } = require('./lib/mindlore-common.cjs');
|
|
7
|
+
const { safeMkdir, safeWriteFile } = require('./lib/secure-io.cjs');
|
|
8
|
+
const { runReadGuard } = require('../../dist/scripts/lib/read-guard-core.js');
|
|
18
9
|
|
|
19
10
|
function main() {
|
|
20
11
|
const baseDir = findMindloreDir();
|
|
@@ -23,64 +14,33 @@ function main() {
|
|
|
23
14
|
const filePath = readHookStdin(['file_path', 'path']);
|
|
24
15
|
if (!filePath) return;
|
|
25
16
|
|
|
26
|
-
// Only track CWD-relative files, skip .mindlore/ internals
|
|
27
17
|
const cwd = process.cwd();
|
|
28
18
|
const resolved = path.resolve(filePath);
|
|
29
19
|
if (!resolved.startsWith(cwd)) return;
|
|
30
20
|
if (resolved.startsWith(path.resolve(baseDir))) return;
|
|
31
21
|
|
|
32
|
-
// Load or create session reads tracker
|
|
33
22
|
const diaryDir = path.join(baseDir, 'diary');
|
|
34
|
-
|
|
35
|
-
fs.mkdirSync(diaryDir, { recursive: true });
|
|
36
|
-
}
|
|
23
|
+
safeMkdir(diaryDir);
|
|
37
24
|
|
|
38
25
|
const readsPath = path.join(diaryDir, `_session-reads-${getProjectName()}.json`);
|
|
39
26
|
let reads = {};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
27
|
+
try {
|
|
28
|
+
reads = JSON.parse(fs.readFileSync(readsPath, 'utf8'));
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.code !== 'ENOENT') hookLog('read-guard', 'warn', `read error: ${err.message}`);
|
|
31
|
+
reads = {};
|
|
46
32
|
}
|
|
47
33
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Support both old format (number) and new format (object with tokens)
|
|
52
|
-
let count, tokens;
|
|
53
|
-
if (typeof existing === 'number') {
|
|
54
|
-
count = existing + 1;
|
|
55
|
-
tokens = 0;
|
|
56
|
-
reads[normalizedPath] = { count, tokens: 0, chars: 0 };
|
|
57
|
-
} else if (existing && typeof existing === 'object') {
|
|
58
|
-
count = (existing.count || 0) + 1;
|
|
59
|
-
tokens = existing.tokens || 0;
|
|
60
|
-
existing.count = count;
|
|
61
|
-
reads[normalizedPath] = existing;
|
|
62
|
-
} else {
|
|
63
|
-
count = 1;
|
|
64
|
-
tokens = 0;
|
|
65
|
-
reads[normalizedPath] = { count, tokens: 0, chars: 0 };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Write updated reads
|
|
69
|
-
fs.writeFileSync(readsPath, JSON.stringify(reads, null, 2), 'utf8');
|
|
70
|
-
|
|
71
|
-
const basename = path.basename(filePath);
|
|
72
|
-
const tokenInfo = tokens > 0 ? ` (~${tokens} token)` : '';
|
|
34
|
+
const decision = runReadGuard({ filePath: resolved, basename: path.basename(filePath) }, reads);
|
|
35
|
+
reads[resolved] = decision.updatedReadsEntry;
|
|
36
|
+
safeWriteFile(readsPath, JSON.stringify(reads, null, 2));
|
|
73
37
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const totalWaste = tokens > 0 ? ` Toplam israf: ~${tokens * (count - 1)} token.` : '';
|
|
77
|
-
process.stderr.write(`[Mindlore BLOCK] ${basename}${tokenInfo} bu session'da ${count}. kez okunuyor.${totalWaste} Edit icin gerekiyorsa once degisikligini yap, sonra tekrar oku. Analiz icin ctx_execute_file kullan.`);
|
|
38
|
+
if (decision.block) {
|
|
39
|
+
process.stderr.write(decision.warning);
|
|
78
40
|
process.exit(2);
|
|
79
41
|
}
|
|
80
42
|
|
|
81
|
-
|
|
82
|
-
if (count > 1) {
|
|
83
|
-
const totalWaste = tokens > 0 ? ` Toplam tekrar: ~${tokens * (count - 1)} token.` : '';
|
|
43
|
+
if (decision.additionalContext) {
|
|
84
44
|
let skeletonSection = '';
|
|
85
45
|
try {
|
|
86
46
|
const ext = path.extname(filePath).slice(1);
|
|
@@ -96,7 +56,7 @@ function main() {
|
|
|
96
56
|
process.stdout.write(JSON.stringify({
|
|
97
57
|
hookSpecificOutput: {
|
|
98
58
|
hookEventName: 'PreToolUse',
|
|
99
|
-
additionalContext:
|
|
59
|
+
additionalContext: decision.additionalContext + skeletonSection
|
|
100
60
|
}
|
|
101
61
|
}));
|
|
102
62
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const { getAllDbs, openDatabase, extractHeadings, readConfig, hookLog, incrementRecallCount, withTelemetry } = require('./lib/mindlore-common.cjs');
|
|
15
|
+
const { safeMkdir, safeWriteFile } = require('./lib/secure-io.cjs');
|
|
15
16
|
|
|
16
17
|
const MAX_RESULTS = 3;
|
|
17
18
|
const MIN_QUERY_WORDS = 3;
|
|
@@ -30,22 +31,42 @@ try {
|
|
|
30
31
|
// search-cache not built yet
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
let TokenEstimatorMod;
|
|
35
|
+
try {
|
|
36
|
+
TokenEstimatorMod = require('../dist/scripts/lib/transcript-token-estimator.js');
|
|
37
|
+
} catch (_err) {
|
|
38
|
+
// estimator not built yet
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
function parseStdin() {
|
|
34
42
|
try {
|
|
35
43
|
const raw = fs.readFileSync(0, 'utf8').trim();
|
|
36
|
-
if (!raw) return { userMessage: '', sessionId: 'unknown' };
|
|
44
|
+
if (!raw) return { userMessage: '', sessionId: 'unknown', transcriptPath: undefined };
|
|
37
45
|
const parsed = JSON.parse(raw);
|
|
38
46
|
const userMessage = parsed.prompt || parsed.content || parsed.message || parsed.query || raw;
|
|
39
47
|
const sessionId = parsed.session_id || 'unknown';
|
|
40
|
-
|
|
48
|
+
const transcriptPath = parsed.transcript_path || parsed.transcriptPath;
|
|
49
|
+
return { userMessage, sessionId, transcriptPath };
|
|
41
50
|
} catch (_err) {
|
|
42
|
-
return { userMessage: '', sessionId: 'unknown' };
|
|
51
|
+
return { userMessage: '', sessionId: 'unknown', transcriptPath: undefined };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getBaseMax(transcriptPath) {
|
|
56
|
+
if (TokenEstimatorMod) {
|
|
57
|
+
try {
|
|
58
|
+
return TokenEstimatorMod.adaptiveResultCount(transcriptPath);
|
|
59
|
+
} catch (_err) {
|
|
60
|
+
// fall through to default
|
|
61
|
+
}
|
|
43
62
|
}
|
|
63
|
+
return MAX_RESULTS;
|
|
44
64
|
}
|
|
45
65
|
|
|
46
66
|
function main() {
|
|
47
|
-
const { userMessage, sessionId } = parseStdin();
|
|
67
|
+
const { userMessage, sessionId, transcriptPath } = parseStdin();
|
|
48
68
|
if (!userMessage || userMessage.length < MIN_QUERY_WORDS) return;
|
|
69
|
+
const baseMax = getBaseMax(transcriptPath);
|
|
49
70
|
let searchMs = 0;
|
|
50
71
|
|
|
51
72
|
const dbPaths = getAllDbs();
|
|
@@ -61,18 +82,26 @@ function main() {
|
|
|
61
82
|
const synonyms = (config && config.synonyms) ? config.synonyms : {};
|
|
62
83
|
|
|
63
84
|
const allResults = [];
|
|
85
|
+
// Track tightest throttle cap across DBs — applied to the final result slice
|
|
86
|
+
// so cache hits (which return previously-stored arrays) still respect throttle
|
|
87
|
+
// state in subsequent calls of the same session.
|
|
88
|
+
let sessionEffectiveMax = baseMax;
|
|
64
89
|
for (const dbPath of dbPaths) {
|
|
65
90
|
const db = openDatabase(dbPath);
|
|
66
91
|
if (!db) continue;
|
|
67
92
|
try {
|
|
68
93
|
// Cache + throttle
|
|
69
94
|
let cache;
|
|
70
|
-
let effectiveMax =
|
|
95
|
+
let effectiveMax = baseMax;
|
|
71
96
|
if (SearchCacheMod) {
|
|
72
97
|
cache = new SearchCacheMod.SearchCache(db, { ttlMs: 300000 });
|
|
73
98
|
const throttle = new SearchCacheMod.SearchThrottle(db);
|
|
74
99
|
const callCount = throttle.incrementCallCount(sessionId);
|
|
75
|
-
|
|
100
|
+
// Throttle is baseMax-aware: when callCount <= 10 it returns baseMax,
|
|
101
|
+
// so adaptive expansion (up to 5 in low-context sessions) is honored.
|
|
102
|
+
// Above 10 calls it clamps to 1, above 20 to 0 (skip).
|
|
103
|
+
effectiveMax = throttle.getMaxResults(callCount, baseMax);
|
|
104
|
+
if (effectiveMax < sessionEffectiveMax) sessionEffectiveMax = effectiveMax;
|
|
76
105
|
if (effectiveMax === 0) {
|
|
77
106
|
hookLog('search', 'info', `Throttled (call #${callCount})`);
|
|
78
107
|
db.close();
|
|
@@ -81,7 +110,7 @@ function main() {
|
|
|
81
110
|
const cached = cache.get(userMessage);
|
|
82
111
|
if (cached) {
|
|
83
112
|
const baseDir = path.dirname(dbPath);
|
|
84
|
-
for (const r of cached) allResults.push({ ...r, baseDir });
|
|
113
|
+
for (const r of cached.slice(0, effectiveMax)) allResults.push({ ...r, baseDir });
|
|
85
114
|
db.close();
|
|
86
115
|
continue;
|
|
87
116
|
}
|
|
@@ -129,7 +158,7 @@ function main() {
|
|
|
129
158
|
|
|
130
159
|
// Sort by score descending, take top N
|
|
131
160
|
unique.sort((a, b) => b.score - a.score);
|
|
132
|
-
const relevant = unique.slice(0,
|
|
161
|
+
const relevant = unique.slice(0, sessionEffectiveMax);
|
|
133
162
|
if (relevant.length === 0) return;
|
|
134
163
|
|
|
135
164
|
// Token budget from config
|
|
@@ -172,7 +201,7 @@ function main() {
|
|
|
172
201
|
if (outputStr.length > OFFLOAD_THRESHOLD) {
|
|
173
202
|
const baseDir = path.dirname(dbPaths[0]);
|
|
174
203
|
const tmpDir = path.join(baseDir, 'tmp');
|
|
175
|
-
|
|
204
|
+
safeMkdir(tmpDir);
|
|
176
205
|
|
|
177
206
|
try {
|
|
178
207
|
const oneHourAgo = Date.now() - 3600000;
|
|
@@ -188,7 +217,7 @@ function main() {
|
|
|
188
217
|
} catch { /* cleanup is best-effort */ }
|
|
189
218
|
const fileName = `search-${Date.now()}.md`;
|
|
190
219
|
const filePath = path.join(tmpDir, fileName);
|
|
191
|
-
|
|
220
|
+
safeWriteFile(filePath, outputStr);
|
|
192
221
|
|
|
193
222
|
const summary = outputStr.slice(0, 500).replace(/\n/g, ' ').trim();
|
|
194
223
|
outputStr = `[Mindlore Search: ${outputStr.length} chars offloaded to ${filePath}]\n` +
|
|
@@ -13,7 +13,7 @@ const fs = require('fs');
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
15
|
const { execFileSync, spawn } = require('child_process');
|
|
16
|
-
const { safeWriteFile, safeWriteJson } = require('
|
|
16
|
+
const { safeMkdir, safeWriteFile, safeWriteJson } = require('./lib/secure-io.cjs');
|
|
17
17
|
const { findMindloreDir, globalDir, getProjectName, openDatabase, ensureEpisodesTable, hasEpisodesTable, insertBareEpisode, insertFtsRow, hookLog, SHARED_EXPORT_DIRS, resolveWin32Bin, withTelemetry, getUnpromotedRawFiles, cleanupExpiredInjectLog } = require('./lib/mindlore-common.cjs');
|
|
18
18
|
|
|
19
19
|
const EXPORT_DIRS = SHARED_EXPORT_DIRS;
|
|
@@ -151,9 +151,7 @@ function main() {
|
|
|
151
151
|
if (!baseDir) return;
|
|
152
152
|
|
|
153
153
|
const diaryDir = path.join(baseDir, 'diary');
|
|
154
|
-
|
|
155
|
-
fs.mkdirSync(diaryDir, { recursive: true });
|
|
156
|
-
}
|
|
154
|
+
safeMkdir(diaryDir);
|
|
157
155
|
|
|
158
156
|
const now = new Date();
|
|
159
157
|
const dateStr = formatDate(now);
|
|
@@ -323,7 +321,7 @@ function writeBareEpisode(baseDir, project, commits, changedFiles, reads) {
|
|
|
323
321
|
*/
|
|
324
322
|
function writeEpisodeFile(baseDir, project, commits, changedFiles, reads) {
|
|
325
323
|
const projDir = path.join(baseDir, 'diary', project || 'unknown');
|
|
326
|
-
|
|
324
|
+
safeMkdir(projDir);
|
|
327
325
|
|
|
328
326
|
const now = process.env.MINDLORE_EPISODE_TS ? new Date(process.env.MINDLORE_EPISODE_TS) : new Date();
|
|
329
327
|
const ts = formatDate(now);
|
|
@@ -406,7 +404,7 @@ function exportMdFile(srcPath, destPath, convertFn) {
|
|
|
406
404
|
}
|
|
407
405
|
let content = fs.readFileSync(srcPath, 'utf8');
|
|
408
406
|
content = convertFn(content);
|
|
409
|
-
|
|
407
|
+
safeWriteFile(destPath, content);
|
|
410
408
|
return true;
|
|
411
409
|
}
|
|
412
410
|
|
|
@@ -434,7 +432,7 @@ function syncObsidian(baseDir) {
|
|
|
434
432
|
|
|
435
433
|
function walkAndExport(srcDir, destDir) {
|
|
436
434
|
if (!fs.existsSync(srcDir)) return;
|
|
437
|
-
|
|
435
|
+
safeMkdir(destDir);
|
|
438
436
|
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
439
437
|
if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
|
|
440
438
|
const srcPath = path.join(srcDir, entry.name);
|
|
@@ -454,7 +452,7 @@ function syncObsidian(baseDir) {
|
|
|
454
452
|
for (const rootFile of ['INDEX.md', 'log.md']) {
|
|
455
453
|
const srcPath = path.join(baseDir, rootFile);
|
|
456
454
|
if (!fs.existsSync(srcPath)) continue;
|
|
457
|
-
|
|
455
|
+
safeMkdir(destBase);
|
|
458
456
|
if (exportMdFile(srcPath, path.join(destBase, rootFile), convertFn)) exported++;
|
|
459
457
|
}
|
|
460
458
|
|
|
@@ -12,7 +12,7 @@ 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, getNominationCounts, resolveMindloreHome } = require('./lib/mindlore-common.cjs');
|
|
14
14
|
const { loadLearningsBlock } = require('./lib/learnings-loader.cjs');
|
|
15
|
-
const { shouldNudgeReflect } = require('../lib/reflect-trigger.cjs');
|
|
15
|
+
const { shouldNudgeReflect, buildNudgeMessage } = require('../lib/reflect-trigger.cjs');
|
|
16
16
|
|
|
17
17
|
function truncateSection(content, sectionRegex, keepCount, label) {
|
|
18
18
|
const match = content.match(sectionRegex);
|
|
@@ -138,10 +138,16 @@ function main() {
|
|
|
138
138
|
// Inject INDEX.md
|
|
139
139
|
const tIndex = Date.now();
|
|
140
140
|
const indexPath = path.join(baseDir, 'INDEX.md');
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
let indexContent;
|
|
142
|
+
try {
|
|
143
|
+
indexContent = fs.readFileSync(indexPath, 'utf8').trim();
|
|
144
|
+
} catch (err) {
|
|
145
|
+
if (err.code !== 'ENOENT') throw err;
|
|
146
|
+
indexContent = null;
|
|
147
|
+
}
|
|
148
|
+
if (indexContent !== null) {
|
|
149
|
+
sourceChars += indexContent.length;
|
|
150
|
+
output.push(`[Mindlore INDEX]\n${indexContent}`);
|
|
145
151
|
}
|
|
146
152
|
timings.index_read = Date.now() - tIndex;
|
|
147
153
|
|
|
@@ -181,15 +187,13 @@ function main() {
|
|
|
181
187
|
// Both are flat strings written by init — no JSON parse needed on session start
|
|
182
188
|
const versionPath = path.join(baseDir, '.version');
|
|
183
189
|
const pkgVersionPath = path.join(baseDir, '.pkg-version');
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
} catch (_err) { /* skip */ }
|
|
190
|
+
let installed;
|
|
191
|
+
try { installed = fs.readFileSync(versionPath, 'utf8').trim(); } catch (err) { if (err.code !== 'ENOENT') throw err; }
|
|
192
|
+
let pkgVersion;
|
|
193
|
+
try { pkgVersion = fs.readFileSync(pkgVersionPath, 'utf8').trim(); } catch (err) { if (err.code !== 'ENOENT') throw err; }
|
|
194
|
+
if (installed !== undefined && pkgVersion !== undefined && pkgVersion !== installed) {
|
|
195
|
+
output.push(`[Mindlore: Guncelleme mevcut (${installed} → ${pkgVersion}). \`npx mindlore init\` calistirin.]`);
|
|
196
|
+
}
|
|
193
197
|
timings.version_check = Date.now() - tVersion;
|
|
194
198
|
|
|
195
199
|
// v0.5.4: Consolidated session payload (replaces scattered episodes/activity/alerts injection)
|
|
@@ -220,14 +224,18 @@ function main() {
|
|
|
220
224
|
|
|
221
225
|
// Auto-reflect nudge (7-day threshold + 24h cooldown)
|
|
222
226
|
try {
|
|
223
|
-
const
|
|
224
|
-
"SELECT value FROM skill_memory WHERE skill_name = 'mindlore-reflect' AND key
|
|
225
|
-
).
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
const rows = db.prepare(
|
|
228
|
+
"SELECT key, value FROM skill_memory WHERE skill_name = 'mindlore-reflect' AND key IN ('last_reflect_date', 'last_nudge_date')"
|
|
229
|
+
).all();
|
|
230
|
+
const byKey = Object.fromEntries(rows.map(r => [r.key, r.value]));
|
|
231
|
+
const reflectRow = byKey['last_reflect_date'] ? { value: byKey['last_reflect_date'] } : undefined;
|
|
232
|
+
const nudgeRow = byKey['last_nudge_date'] ? { value: byKey['last_nudge_date'] } : undefined;
|
|
229
233
|
if (shouldNudgeReflect(reflectRow?.value ?? null, nudgeRow?.value ?? null, new Date())) {
|
|
230
|
-
|
|
234
|
+
const daysSince = reflectRow?.value ? Math.floor((Date.now() - new Date(reflectRow.value).getTime()) / 86400000) : 999;
|
|
235
|
+
const episodeCount = hasEpisodesTable(db) ? db.prepare("SELECT count(*) AS c FROM episodes").get()?.c ?? 0 : 0;
|
|
236
|
+
const diaryDirPath = path.join(baseDir, 'diary');
|
|
237
|
+
const diaryCount = fs.existsSync(diaryDirPath) ? fs.readdirSync(diaryDirPath).length : 0;
|
|
238
|
+
output.push(buildNudgeMessage({ daysSince, episodeCount, diaryCount }));
|
|
231
239
|
const nowIso = new Date().toISOString();
|
|
232
240
|
db.prepare(`
|
|
233
241
|
INSERT INTO skill_memory (skill_name, key, value, updated_at)
|
package/mcp-server.cjs
CHANGED
|
@@ -12481,12 +12481,12 @@ var require_dist = __commonJS({
|
|
|
12481
12481
|
throw new Error(`Unknown format "${name}"`);
|
|
12482
12482
|
return f;
|
|
12483
12483
|
};
|
|
12484
|
-
function addFormats(ajv, list,
|
|
12484
|
+
function addFormats(ajv, list, fs10, exportName) {
|
|
12485
12485
|
var _a3;
|
|
12486
12486
|
var _b;
|
|
12487
12487
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
12488
12488
|
for (const f of list)
|
|
12489
|
-
ajv.addFormat(f,
|
|
12489
|
+
ajv.addFormat(f, fs10[f]);
|
|
12490
12490
|
}
|
|
12491
12491
|
module2.exports = exports2 = formatsPlugin;
|
|
12492
12492
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -36561,7 +36561,7 @@ var StdioServerTransport = class {
|
|
|
36561
36561
|
};
|
|
36562
36562
|
|
|
36563
36563
|
// scripts/mcp-server.ts
|
|
36564
|
-
var
|
|
36564
|
+
var import_fs9 = __toESM(require("fs"));
|
|
36565
36565
|
var import_path9 = __toESM(require("path"));
|
|
36566
36566
|
|
|
36567
36567
|
// scripts/lib/mcp-namespace.ts
|
|
@@ -36798,6 +36798,7 @@ var PRIORITY_CASE = "WHEN 'supersedes' THEN 1 WHEN 'contradicts' THEN 2 WHEN 'ex
|
|
|
36798
36798
|
var CC_PLUGIN_CACHE_DIR = import_path.default.join(import_os.default.homedir(), ".claude", "plugins", "cache");
|
|
36799
36799
|
var CC_MEMORY_PATH_MARKER = import_path.default.join(".claude", "projects");
|
|
36800
36800
|
var TELEMETRY_FILE_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
36801
|
+
var CACHE_STALE_AGE_MS = 24 * 3600 * 1e3;
|
|
36801
36802
|
|
|
36802
36803
|
// scripts/lib/mcp-namespace.ts
|
|
36803
36804
|
function resolveMindloreHome() {
|
|
@@ -37488,7 +37489,7 @@ function handleBrief(ctx, input) {
|
|
|
37488
37489
|
}
|
|
37489
37490
|
|
|
37490
37491
|
// scripts/lib/tool-adapters/ingest-adapter.ts
|
|
37491
|
-
var
|
|
37492
|
+
var import_fs5 = __toESM(require("fs"));
|
|
37492
37493
|
var import_path6 = __toESM(require("path"));
|
|
37493
37494
|
|
|
37494
37495
|
// scripts/lib/slugify.ts
|
|
@@ -37496,6 +37497,15 @@ function slugify2(text) {
|
|
|
37496
37497
|
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 60).replace(/^-|-$/g, "");
|
|
37497
37498
|
}
|
|
37498
37499
|
|
|
37500
|
+
// scripts/lib/secure-io.ts
|
|
37501
|
+
var import_fs4 = __toESM(require("fs"));
|
|
37502
|
+
function safeMkdir(dirPath) {
|
|
37503
|
+
import_fs4.default.mkdirSync(dirPath, { recursive: true, mode: 448 });
|
|
37504
|
+
}
|
|
37505
|
+
function safeWriteFile(filePath, data) {
|
|
37506
|
+
import_fs4.default.writeFileSync(filePath, data, { encoding: "utf8", mode: 384 });
|
|
37507
|
+
}
|
|
37508
|
+
|
|
37499
37509
|
// scripts/lib/tool-adapters/ingest-adapter.ts
|
|
37500
37510
|
function handleIngest(ctx, input) {
|
|
37501
37511
|
if (!input.content || input.content.trim().length === 0) {
|
|
@@ -37506,7 +37516,7 @@ function handleIngest(ctx, input) {
|
|
|
37506
37516
|
if (input.type === "file") {
|
|
37507
37517
|
const filePath = import_path6.default.resolve(input.content);
|
|
37508
37518
|
try {
|
|
37509
|
-
body =
|
|
37519
|
+
body = import_fs5.default.readFileSync(filePath, "utf8").replace(/\r\n/g, "\n");
|
|
37510
37520
|
} catch {
|
|
37511
37521
|
throw new Error(`File not found: ${filePath}`);
|
|
37512
37522
|
}
|
|
@@ -37534,8 +37544,8 @@ ${body}
|
|
|
37534
37544
|
`;
|
|
37535
37545
|
const outPath = import_path6.default.join(ctx.baseDir, "raw", `${slug}.md`);
|
|
37536
37546
|
const rawDir = import_path6.default.join(ctx.baseDir, "raw");
|
|
37537
|
-
|
|
37538
|
-
|
|
37547
|
+
safeMkdir(rawDir);
|
|
37548
|
+
safeWriteFile(outPath, fullContent);
|
|
37539
37549
|
const wordCount = body.split(/\s+/).filter(Boolean).length;
|
|
37540
37550
|
return {
|
|
37541
37551
|
slug,
|
|
@@ -37547,7 +37557,7 @@ ${body}
|
|
|
37547
37557
|
}
|
|
37548
37558
|
|
|
37549
37559
|
// scripts/lib/tool-adapters/decide-adapter.ts
|
|
37550
|
-
var
|
|
37560
|
+
var import_fs6 = __toESM(require("fs"));
|
|
37551
37561
|
var import_path7 = __toESM(require("path"));
|
|
37552
37562
|
function handleDecide(ctx, input) {
|
|
37553
37563
|
if (input.action === "save") {
|
|
@@ -37556,7 +37566,7 @@ function handleDecide(ctx, input) {
|
|
|
37556
37566
|
}
|
|
37557
37567
|
}
|
|
37558
37568
|
const decisionsDir = import_path7.default.join(ctx.baseDir, "decisions");
|
|
37559
|
-
|
|
37569
|
+
safeMkdir(decisionsDir);
|
|
37560
37570
|
if (input.action === "save") {
|
|
37561
37571
|
const slug = slugify2(input.title);
|
|
37562
37572
|
if (!slug) throw new Error("Cannot generate slug from title");
|
|
@@ -37578,15 +37588,15 @@ function handleDecide(ctx, input) {
|
|
|
37578
37588
|
}
|
|
37579
37589
|
lines.push("");
|
|
37580
37590
|
const outPath = import_path7.default.join(decisionsDir, `${slug}.md`);
|
|
37581
|
-
|
|
37591
|
+
safeWriteFile(outPath, lines.join("\n"));
|
|
37582
37592
|
return { slug, path: outPath };
|
|
37583
37593
|
}
|
|
37584
|
-
const files =
|
|
37594
|
+
const files = import_fs6.default.readdirSync(decisionsDir).filter((f) => f.endsWith(".md")).sort().reverse();
|
|
37585
37595
|
const limit = Math.min(input.limit ?? 10, 50);
|
|
37586
37596
|
const decisions = [];
|
|
37587
37597
|
for (const file2 of files) {
|
|
37588
37598
|
if (decisions.length >= limit) break;
|
|
37589
|
-
const raw =
|
|
37599
|
+
const raw = import_fs6.default.readFileSync(import_path7.default.join(decisionsDir, file2), "utf8").replace(/\r\n/g, "\n");
|
|
37590
37600
|
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
37591
37601
|
if (!match) continue;
|
|
37592
37602
|
const fmBlock = match[1];
|
|
@@ -37647,12 +37657,12 @@ function handleRelate(ctx, input) {
|
|
|
37647
37657
|
}
|
|
37648
37658
|
|
|
37649
37659
|
// scripts/lib/tool-adapters/get-adapter.ts
|
|
37650
|
-
var
|
|
37660
|
+
var import_fs7 = __toESM(require("fs"));
|
|
37651
37661
|
function handleGet(ctx, input) {
|
|
37652
37662
|
const { path: sourcePath, title } = assertSlugExists(ctx.db, input.source);
|
|
37653
37663
|
let raw;
|
|
37654
37664
|
try {
|
|
37655
|
-
raw =
|
|
37665
|
+
raw = import_fs7.default.readFileSync(sourcePath, "utf8").replace(/\r\n/g, "\n");
|
|
37656
37666
|
} catch {
|
|
37657
37667
|
throw new Error(`Source file not found on disk: ${sourcePath}`);
|
|
37658
37668
|
}
|
|
@@ -37669,10 +37679,16 @@ function handleGet(ctx, input) {
|
|
|
37669
37679
|
const match = chunks.find((c) => c.heading && slugify2(c.heading) === targetSlug);
|
|
37670
37680
|
if (match) {
|
|
37671
37681
|
result.content = match.content;
|
|
37672
|
-
|
|
37682
|
+
const heading = match.heading;
|
|
37683
|
+
if (!heading) throw new Error("expected match.heading to exist");
|
|
37684
|
+
result.section = heading.replace(/^#+\s*/, "");
|
|
37673
37685
|
} else {
|
|
37674
37686
|
result.content = "";
|
|
37675
|
-
const sections = chunks.filter((c) => c.heading).map((c) =>
|
|
37687
|
+
const sections = chunks.filter((c) => c.heading).map((c) => {
|
|
37688
|
+
const heading = c.heading;
|
|
37689
|
+
if (!heading) throw new Error("expected c.heading to exist");
|
|
37690
|
+
return heading.replace(/^#+\s*/, "");
|
|
37691
|
+
});
|
|
37676
37692
|
if (sections.length > 0) result.available_sections = sections;
|
|
37677
37693
|
}
|
|
37678
37694
|
}
|
|
@@ -37685,12 +37701,12 @@ function handleGet(ctx, input) {
|
|
|
37685
37701
|
}
|
|
37686
37702
|
|
|
37687
37703
|
// scripts/lib/mcp-telemetry.ts
|
|
37688
|
-
var
|
|
37704
|
+
var import_fs8 = __toESM(require("fs"));
|
|
37689
37705
|
var import_path8 = __toESM(require("path"));
|
|
37690
37706
|
function writeMcpTelemetry(baseDir, entry) {
|
|
37691
37707
|
try {
|
|
37692
37708
|
const telemetryPath = import_path8.default.join(baseDir, "telemetry.jsonl");
|
|
37693
|
-
|
|
37709
|
+
import_fs8.default.appendFileSync(telemetryPath, JSON.stringify(entry) + "\n");
|
|
37694
37710
|
} catch {
|
|
37695
37711
|
}
|
|
37696
37712
|
}
|
|
@@ -37836,7 +37852,7 @@ function registerAllTools(server, ctx) {
|
|
|
37836
37852
|
function resolvePluginRoot() {
|
|
37837
37853
|
let dir = __dirname;
|
|
37838
37854
|
for (let i = 0; i < 5; i++) {
|
|
37839
|
-
if (
|
|
37855
|
+
if (import_fs9.default.existsSync(import_path9.default.join(dir, "node_modules", "better-sqlite3"))) return dir;
|
|
37840
37856
|
const parent = import_path9.default.dirname(dir);
|
|
37841
37857
|
if (parent === dir) break;
|
|
37842
37858
|
dir = parent;
|
|
@@ -37846,7 +37862,7 @@ function resolvePluginRoot() {
|
|
|
37846
37862
|
function ensureSqliteBinding(root) {
|
|
37847
37863
|
const modDir = import_path9.default.join(root, "node_modules", "better-sqlite3");
|
|
37848
37864
|
const bindingPath = import_path9.default.join(modDir, "build", "Release", "better_sqlite3.node");
|
|
37849
|
-
if (
|
|
37865
|
+
if (import_fs9.default.existsSync(modDir) && !import_fs9.default.existsSync(bindingPath)) {
|
|
37850
37866
|
process.stderr.write("mindlore-mcp: rebuilding better-sqlite3 native binding...\n");
|
|
37851
37867
|
try {
|
|
37852
37868
|
(0, import_child_process.execSync)("npm rebuild better-sqlite3", {
|
|
@@ -37868,8 +37884,8 @@ ensureSqliteBinding(pluginRoot);
|
|
|
37868
37884
|
var Database = require(import_path9.default.join(pluginRoot, "node_modules", "better-sqlite3"));
|
|
37869
37885
|
var PACKAGE_VERSION = (() => {
|
|
37870
37886
|
try {
|
|
37871
|
-
const pkgPath =
|
|
37872
|
-
const pkg = JSON.parse(
|
|
37887
|
+
const pkgPath = import_fs9.default.existsSync(import_path9.default.join(__dirname, "package.json")) ? import_path9.default.join(__dirname, "package.json") : import_path9.default.join(__dirname, "..", "package.json");
|
|
37888
|
+
const pkg = JSON.parse(import_fs9.default.readFileSync(pkgPath, "utf8"));
|
|
37873
37889
|
return pkg.version ?? "0.0.0";
|
|
37874
37890
|
} catch {
|
|
37875
37891
|
return "0.0.0";
|
|
@@ -37877,11 +37893,11 @@ var PACKAGE_VERSION = (() => {
|
|
|
37877
37893
|
})();
|
|
37878
37894
|
async function main() {
|
|
37879
37895
|
const baseDir = resolveMindloreHome();
|
|
37880
|
-
if (!
|
|
37881
|
-
|
|
37896
|
+
if (!import_fs9.default.existsSync(baseDir)) {
|
|
37897
|
+
safeMkdir(baseDir);
|
|
37882
37898
|
for (const sub of ["sources", "episodes", "decisions", "diary", "raw", "domains", "analyses", "learnings"]) {
|
|
37883
37899
|
const dir = import_path9.default.join(baseDir, sub);
|
|
37884
|
-
if (!
|
|
37900
|
+
if (!import_fs9.default.existsSync(dir)) safeMkdir(dir);
|
|
37885
37901
|
}
|
|
37886
37902
|
}
|
|
37887
37903
|
const dbPath = import_path9.default.join(baseDir, DB_NAME);
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifestVersion": 2,
|
|
3
3
|
"name": "mindlore",
|
|
4
4
|
"description": "AI-native knowledge system for Claude Code. Persistent, searchable, evolving knowledge base with FTS5 and Knowledge Graph.",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.7",
|
|
6
6
|
"skills": [
|
|
7
7
|
{
|
|
8
8
|
"name": "mindlore-ingest",
|
|
@@ -58,6 +58,11 @@
|
|
|
58
58
|
"name": "mindlore-stats",
|
|
59
59
|
"path": "skills/mindlore-stats/SKILL.md",
|
|
60
60
|
"description": "Show context contribution and cost per session — hook calls, durations, DB stats."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "mindlore-learnings",
|
|
64
|
+
"path": "skills/mindlore-learnings/SKILL.md",
|
|
65
|
+
"description": "Show full content of a learning by slug, or list all learnings. Use when the session-focus hook truncates a learning and you need the full text."
|
|
61
66
|
}
|
|
62
67
|
],
|
|
63
68
|
"agents": [
|
|
@@ -193,3 +193,24 @@ Optional: run full health check for structural integrity:
|
|
|
193
193
|
```bash
|
|
194
194
|
node "$MINDLORE_PKG/dist/scripts/lib/skill-runner.js" mindlore-ingest mindlore-health-check.js
|
|
195
195
|
```
|
|
196
|
+
|
|
197
|
+
## Type-Aware Extraction Templates
|
|
198
|
+
|
|
199
|
+
The default extraction template produces generic summary + tags. For specific source types, use the matching template below.
|
|
200
|
+
|
|
201
|
+
### github-repo
|
|
202
|
+
Required fields in the source summary:
|
|
203
|
+
- **Tech Stack:** languages, frameworks, key dependencies
|
|
204
|
+
- **Key Features:** 3-5 main features the README emphasizes
|
|
205
|
+
- **Setup:** install/run commands
|
|
206
|
+
- **License:** SPDX identifier
|
|
207
|
+
|
|
208
|
+
### cc-session
|
|
209
|
+
Required fields:
|
|
210
|
+
- **Decisions:** numbered list of architectural/scope decisions made
|
|
211
|
+
- **Patterns:** recurring techniques, idioms, or anti-patterns observed
|
|
212
|
+
- **Actionable Items:** TODO / follow-up tasks named in the transcript
|
|
213
|
+
- **Open Questions:** unresolved items called out at session end
|
|
214
|
+
|
|
215
|
+
### Other types (docs, blog, video, x-thread, text-paste, snippet, forum, cc-subagent)
|
|
216
|
+
Use the existing generic template (summary + tags + quality + related links).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mindlore-learnings
|
|
3
|
+
description: Show full content of a learning by slug, or list all learnings. Use when the session-focus hook truncates a learning and you need the full text.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# mindlore-learnings
|
|
7
|
+
|
|
8
|
+
## Commands
|
|
9
|
+
|
|
10
|
+
### show <slug>
|
|
11
|
+
Returns full content of `~/.mindlore/learnings/<slug>.md`.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
```
|
|
15
|
+
/mindlore-learnings show dev-patterns-2026-04
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If slug not found, suggests closest match.
|
|
19
|
+
|
|
20
|
+
### list
|
|
21
|
+
Lists all learnings with the first line of each.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
/mindlore-learnings list
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Implementation
|
|
28
|
+
|
|
29
|
+
Source: `scripts/mindlore-learnings.ts`
|
|
30
|
+
Use: `node "$MINDLORE_PKG/dist/scripts/lib/skill-runner.js" mindlore-learnings mindlore-learnings.js <command> [args]`
|
package/start.cjs
CHANGED
|
@@ -85,7 +85,7 @@ function installMissing(packages) {
|
|
|
85
85
|
try {
|
|
86
86
|
execSync(
|
|
87
87
|
`${NPM} install ${packages.join(' ')} --no-package-lock --no-save --silent`,
|
|
88
|
-
{ cwd: __dirname_, stdio: 'pipe', timeout:
|
|
88
|
+
{ cwd: __dirname_, stdio: 'pipe', timeout: 600000, shell: true }
|
|
89
89
|
);
|
|
90
90
|
log('install complete');
|
|
91
91
|
return true;
|