mindlore 0.7.0 → 0.7.1
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 +30 -3
- package/dist/scripts/bundle-hooks.d.ts +2 -0
- package/dist/scripts/bundle-hooks.d.ts.map +1 -0
- package/dist/scripts/bundle-hooks.js +68 -0
- package/dist/scripts/bundle-hooks.js.map +1 -0
- package/dist/scripts/init.js +0 -3
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +0 -2
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +0 -21
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/tests/hook-smoke.test.js +1 -1
- package/dist/tests/hook-smoke.test.js.map +1 -1
- package/dist/tests/search-hook.test.js +1 -1
- package/dist/tests/search-hook.test.js.map +1 -1
- package/hooks/cc-memory-bulk-sync.cjs +592 -0
- package/hooks/cc-session-sync.cjs +842 -0
- package/hooks/hooks.json +149 -0
- package/hooks/lib/mindlore-common.cjs +2 -2
- package/hooks/lib/secure-io.cjs +17 -0
- package/hooks/mindlore-cwd-changed.cjs +19 -34
- package/hooks/mindlore-decision-detector.cjs +40 -31
- package/hooks/mindlore-dont-repeat.cjs +57 -115
- package/hooks/mindlore-fts5-sync.cjs +15 -44
- package/hooks/mindlore-index.cjs +100 -101
- package/hooks/mindlore-model-router.cjs +20 -32
- package/hooks/mindlore-post-compact.cjs +26 -42
- package/hooks/mindlore-post-read.cjs +35 -60
- package/hooks/mindlore-pre-compact.cjs +55 -73
- package/hooks/mindlore-read-guard.cjs +28 -51
- package/hooks/mindlore-research-guard.cjs +63 -101
- package/hooks/mindlore-search.cjs +1142 -93
- package/hooks/mindlore-session-end.cjs +155 -276
- package/hooks/mindlore-session-focus.cjs +639 -110
- package/hooks/src/lib/constants.cjs +15 -0
- package/hooks/src/lib/mindlore-common.cjs +975 -0
- package/hooks/src/lib/mindlore-common.d.cts +72 -0
- package/hooks/src/lib/secure-io.cjs +17 -0
- package/hooks/src/lib/types.d.ts +58 -0
- package/hooks/src/mindlore-cwd-changed.cjs +57 -0
- package/hooks/src/mindlore-decision-detector.cjs +54 -0
- package/hooks/src/mindlore-dont-repeat.cjs +222 -0
- package/hooks/src/mindlore-fts5-sync.cjs +98 -0
- package/hooks/src/mindlore-index.cjs +230 -0
- package/hooks/src/mindlore-model-router.cjs +54 -0
- package/hooks/src/mindlore-post-compact.cjs +69 -0
- package/hooks/src/mindlore-post-read.cjs +106 -0
- package/hooks/src/mindlore-pre-compact.cjs +154 -0
- package/hooks/src/mindlore-read-guard.cjs +105 -0
- package/hooks/src/mindlore-research-guard.cjs +176 -0
- package/hooks/src/mindlore-search.cjs +200 -0
- package/hooks/src/mindlore-session-end.cjs +511 -0
- package/hooks/src/mindlore-session-focus.cjs +256 -0
- package/package.json +7 -3
- package/plugin.json +3 -3
- package/templates/config.json +1 -1
|
@@ -1,256 +1,785 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
"use strict";
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
5
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
6
|
+
};
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// dist/scripts/lib/session-payload.js
|
|
9
|
+
var require_session_payload = __commonJS({
|
|
10
|
+
"dist/scripts/lib/session-payload.js"(exports2) {
|
|
11
|
+
"use strict";
|
|
12
|
+
var __importDefault = exports2 && exports2.__importDefault || function(mod) {
|
|
13
|
+
return mod && mod.__esModule ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
16
|
+
exports2.buildSessionPayload = buildSessionPayload;
|
|
17
|
+
var fs_1 = __importDefault(require("fs"));
|
|
18
|
+
var path_1 = __importDefault(require("path"));
|
|
19
|
+
var crypto_1 = __importDefault(require("crypto"));
|
|
20
|
+
var CHARS_PER_TOKEN = 4;
|
|
21
|
+
function estimateTokens(text) {
|
|
22
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
23
|
+
}
|
|
24
|
+
function buildSessionSummary(baseDir, latestDeltaContent) {
|
|
25
|
+
if (latestDeltaContent) {
|
|
26
|
+
const lines2 = latestDeltaContent.split("\n").filter((l) => l.startsWith("- ") || l.startsWith("# "));
|
|
27
|
+
return lines2.slice(0, 10).join("\n") || "No previous session data.";
|
|
28
|
+
}
|
|
29
|
+
const diaryDir = path_1.default.join(baseDir, "diary");
|
|
30
|
+
if (!fs_1.default.existsSync(diaryDir))
|
|
31
|
+
return "No previous session data.";
|
|
32
|
+
const deltas = fs_1.default.readdirSync(diaryDir).filter((f) => f.startsWith("delta-")).sort();
|
|
33
|
+
if (deltas.length === 0)
|
|
34
|
+
return "No previous session data.";
|
|
35
|
+
const latestFile = deltas[deltas.length - 1] ?? "";
|
|
36
|
+
const latest = fs_1.default.readFileSync(path_1.default.join(diaryDir, latestFile), "utf8");
|
|
37
|
+
const lines = latest.split("\n").filter((l) => l.startsWith("- ") || l.startsWith("# "));
|
|
38
|
+
return lines.slice(0, 10).join("\n");
|
|
39
|
+
}
|
|
40
|
+
function buildEpisodeSections(db, project, sessionId) {
|
|
41
|
+
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString();
|
|
42
|
+
const dedupClause = sessionId ? "AND rowid NOT IN (SELECT episode_id FROM episode_inject_log WHERE session_id = ?)" : "";
|
|
43
|
+
const query = `SELECT rowid, kind, summary, created_at FROM episodes
|
|
44
|
+
WHERE status = 'active' AND project = ?
|
|
45
|
+
AND kind IN ('decision', 'friction', 'learning')
|
|
46
|
+
AND created_at >= ?
|
|
47
|
+
${dedupClause}
|
|
48
|
+
ORDER BY kind, created_at DESC`;
|
|
49
|
+
const params = sessionId ? [project, sevenDaysAgo, sessionId] : [project, sevenDaysAgo];
|
|
50
|
+
const rawRows = db.prepare(query).all(...params);
|
|
51
|
+
const rows = rawRows;
|
|
52
|
+
if (sessionId && rows.length > 0) {
|
|
53
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
54
|
+
const insert = db.prepare(`INSERT OR IGNORE INTO episode_inject_log (session_id, episode_id, injected_at) VALUES (?, ?, ?)`);
|
|
55
|
+
db.transaction(() => {
|
|
56
|
+
for (const row of rows) {
|
|
57
|
+
insert.run(sessionId, row.rowid, now);
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
}
|
|
61
|
+
const grouped = { decision: [], friction: [], learning: [] };
|
|
62
|
+
for (const row of rows) {
|
|
63
|
+
const kind = row.kind;
|
|
64
|
+
if (kind === "decision" || kind === "friction" || kind === "learning") {
|
|
65
|
+
grouped[kind].push(row);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const fmt = (items, limit) => items.slice(0, limit).map((r) => `- ${r.summary} (${r.created_at.slice(0, 10)})`).join("\n");
|
|
69
|
+
return {
|
|
70
|
+
decisions: grouped.decision.length > 0 ? fmt(grouped.decision, 5) : "No recent decisions.",
|
|
71
|
+
friction: grouped.friction.length > 0 ? fmt(grouped.friction, 3) : "No active friction points.",
|
|
72
|
+
learnings: grouped.learning.length > 0 ? fmt(grouped.learning, 5) : "No recent learnings."
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function buildSessionPayload(opts) {
|
|
76
|
+
const { db, baseDir, project, tokenBudget = 2e3, latestDeltaContent, sessionId } = opts;
|
|
77
|
+
const sections = [];
|
|
78
|
+
const summary = buildSessionSummary(baseDir, latestDeltaContent);
|
|
79
|
+
sections.push({ label: "Session", content: summary, tokens: estimateTokens(summary) });
|
|
80
|
+
const episodes = buildEpisodeSections(db, project, sessionId);
|
|
81
|
+
sections.push({ label: "Decisions", content: episodes.decisions, tokens: estimateTokens(episodes.decisions) });
|
|
82
|
+
sections.push({ label: "Friction", content: episodes.friction, tokens: estimateTokens(episodes.friction) });
|
|
83
|
+
sections.push({ label: "Learnings", content: episodes.learnings, tokens: estimateTokens(episodes.learnings) });
|
|
84
|
+
try {
|
|
85
|
+
const summaries = db.prepare(`SELECT session_summary, created_at FROM episodes
|
|
86
|
+
WHERE kind = 'session-summary' AND project = ? AND session_summary IS NOT NULL
|
|
87
|
+
ORDER BY created_at DESC LIMIT 3`).all(project);
|
|
88
|
+
if (summaries.length > 0) {
|
|
89
|
+
const content = summaries.map((s) => `- ${s.created_at.slice(0, 16)}: ${s.session_summary}`).join("\n");
|
|
90
|
+
sections.push({ label: "Past Sessions", content: `# Son Sessionlar
|
|
91
|
+
${content}`, tokens: estimateTokens(content) });
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
let totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);
|
|
96
|
+
while (totalTokens > tokenBudget && sections.length > 1) {
|
|
97
|
+
const removed = sections.pop();
|
|
98
|
+
if (!removed)
|
|
99
|
+
break;
|
|
100
|
+
totalTokens -= removed.tokens;
|
|
101
|
+
}
|
|
102
|
+
const allContent = sections.map((s) => s.content).join("|");
|
|
103
|
+
const contentHash = crypto_1.default.createHash("md5").update(allContent).digest("hex").slice(0, 8);
|
|
104
|
+
return { sections, totalTokens, contentHash };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// dist/scripts/lib/migrations-v051.js
|
|
110
|
+
var require_migrations_v051 = __commonJS({
|
|
111
|
+
"dist/scripts/lib/migrations-v051.js"(exports2) {
|
|
112
|
+
"use strict";
|
|
113
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
114
|
+
exports2.V051_MIGRATIONS = void 0;
|
|
115
|
+
exports2.V051_MIGRATIONS = [
|
|
116
|
+
{
|
|
117
|
+
version: 2,
|
|
118
|
+
name: "add_source_type_and_project_scope",
|
|
119
|
+
up: (db) => {
|
|
120
|
+
const cols = db.pragma("table_info(file_hashes)");
|
|
121
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
122
|
+
if (!colNames.has("source_type")) {
|
|
123
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN source_type TEXT DEFAULT 'mindlore'");
|
|
124
|
+
}
|
|
125
|
+
if (!colNames.has("project_scope")) {
|
|
126
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN project_scope TEXT");
|
|
127
|
+
}
|
|
128
|
+
if (!colNames.has("content_hash")) {
|
|
129
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN content_hash TEXT");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// dist/scripts/lib/migrations.js
|
|
138
|
+
var require_migrations = __commonJS({
|
|
139
|
+
"dist/scripts/lib/migrations.js"(exports2) {
|
|
140
|
+
"use strict";
|
|
141
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
142
|
+
exports2.V051_MIGRATIONS = exports2.V050_MIGRATIONS = void 0;
|
|
143
|
+
exports2.V050_MIGRATIONS = [
|
|
144
|
+
{
|
|
145
|
+
version: 1,
|
|
146
|
+
name: "add_vec_table_and_timestamps",
|
|
147
|
+
up: (db) => {
|
|
148
|
+
const cols = db.pragma("table_info(file_hashes)");
|
|
149
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
150
|
+
if (!colNames.has("created_at")) {
|
|
151
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN created_at TEXT");
|
|
152
|
+
}
|
|
153
|
+
if (!colNames.has("updated_at")) {
|
|
154
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN updated_at TEXT");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
];
|
|
159
|
+
var migrations_v051_js_1 = require_migrations_v051();
|
|
160
|
+
Object.defineProperty(exports2, "V051_MIGRATIONS", { enumerable: true, get: function() {
|
|
161
|
+
return migrations_v051_js_1.V051_MIGRATIONS;
|
|
162
|
+
} });
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// dist/scripts/lib/migrations-v052.js
|
|
167
|
+
var require_migrations_v052 = __commonJS({
|
|
168
|
+
"dist/scripts/lib/migrations-v052.js"(exports2) {
|
|
169
|
+
"use strict";
|
|
170
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
171
|
+
exports2.V052_MIGRATIONS = void 0;
|
|
172
|
+
exports2.V052_MIGRATIONS = [
|
|
173
|
+
{
|
|
174
|
+
version: 3,
|
|
175
|
+
name: "add_skill_memory_table",
|
|
176
|
+
up: (db) => {
|
|
177
|
+
db.exec(`
|
|
178
|
+
CREATE TABLE IF NOT EXISTS skill_memory (
|
|
179
|
+
id INTEGER PRIMARY KEY,
|
|
180
|
+
skill_name TEXT NOT NULL,
|
|
181
|
+
key TEXT NOT NULL,
|
|
182
|
+
value TEXT NOT NULL,
|
|
183
|
+
updated_at TEXT NOT NULL,
|
|
184
|
+
access_count INTEGER DEFAULT 0,
|
|
185
|
+
UNIQUE(skill_name, key)
|
|
186
|
+
)
|
|
187
|
+
`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// dist/scripts/lib/migrations-v053.js
|
|
195
|
+
var require_migrations_v053 = __commonJS({
|
|
196
|
+
"dist/scripts/lib/migrations-v053.js"(exports2) {
|
|
197
|
+
"use strict";
|
|
198
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
199
|
+
exports2.V053_MIGRATIONS = void 0;
|
|
200
|
+
exports2.V053_MIGRATIONS = [
|
|
201
|
+
{
|
|
202
|
+
version: 4,
|
|
203
|
+
name: "add_recall_telemetry_and_decay",
|
|
204
|
+
up: (db) => {
|
|
205
|
+
const cols = db.pragma("table_info(file_hashes)");
|
|
206
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
207
|
+
if (!colNames.has("recall_count")) {
|
|
208
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN recall_count INTEGER DEFAULT 0");
|
|
209
|
+
}
|
|
210
|
+
if (!colNames.has("last_recalled_at")) {
|
|
211
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN last_recalled_at TEXT");
|
|
212
|
+
}
|
|
213
|
+
if (!colNames.has("archived_at")) {
|
|
214
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN archived_at TEXT");
|
|
215
|
+
}
|
|
216
|
+
if (!colNames.has("importance")) {
|
|
217
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN importance REAL DEFAULT 1.0");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
version: 5,
|
|
223
|
+
name: "add_episode_consolidation",
|
|
224
|
+
up: (db) => {
|
|
225
|
+
const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='episodes'").get();
|
|
226
|
+
if (!table)
|
|
227
|
+
return;
|
|
228
|
+
const cols = db.pragma("table_info(episodes)");
|
|
229
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
230
|
+
if (!colNames.has("consolidation_status")) {
|
|
231
|
+
db.exec("ALTER TABLE episodes ADD COLUMN consolidation_status TEXT DEFAULT 'raw'");
|
|
232
|
+
}
|
|
233
|
+
if (!colNames.has("consolidated_into")) {
|
|
234
|
+
db.exec("ALTER TABLE episodes ADD COLUMN consolidated_into TEXT");
|
|
235
|
+
}
|
|
236
|
+
if (!colNames.has("decay_score")) {
|
|
237
|
+
db.exec("ALTER TABLE episodes ADD COLUMN decay_score REAL");
|
|
238
|
+
}
|
|
239
|
+
if (!colNames.has("last_decay_calc")) {
|
|
240
|
+
db.exec("ALTER TABLE episodes ADD COLUMN last_decay_calc TEXT");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// dist/scripts/lib/migrations-v061.js
|
|
249
|
+
var require_migrations_v061 = __commonJS({
|
|
250
|
+
"dist/scripts/lib/migrations-v061.js"(exports2) {
|
|
251
|
+
"use strict";
|
|
252
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
253
|
+
exports2.V061_MIGRATIONS = void 0;
|
|
254
|
+
exports2.V061_MIGRATIONS = [
|
|
255
|
+
{
|
|
256
|
+
version: 6,
|
|
257
|
+
name: "cleanup_project_category",
|
|
258
|
+
up: (db) => {
|
|
259
|
+
db.exec(`
|
|
260
|
+
UPDATE mindlore_fts SET project = 'unknown'
|
|
261
|
+
WHERE project LIKE '.mindlore%' OR project LIKE 'C--%'
|
|
262
|
+
`);
|
|
263
|
+
db.exec(`
|
|
264
|
+
UPDATE mindlore_fts SET category = 'cc-subagent'
|
|
265
|
+
WHERE category IN ('subagent', 'cc_subagent')
|
|
266
|
+
`);
|
|
267
|
+
db.exec(`
|
|
268
|
+
UPDATE mindlore_fts SET category = 'cc-session'
|
|
269
|
+
WHERE category IN ('session', 'cc_session')
|
|
270
|
+
`);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
version: 7,
|
|
275
|
+
name: "split_fts_sessions",
|
|
276
|
+
up: (db) => {
|
|
277
|
+
db.exec(`
|
|
278
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS mindlore_fts_sessions USING fts5(
|
|
279
|
+
path, slug, description, type, category, title, content, tags,
|
|
280
|
+
quality, date_captured, project
|
|
281
|
+
)
|
|
282
|
+
`);
|
|
283
|
+
db.exec("BEGIN");
|
|
284
|
+
try {
|
|
285
|
+
db.exec(`
|
|
286
|
+
INSERT INTO mindlore_fts_sessions (path, slug, description, type, category, title, content, tags, quality, date_captured, project)
|
|
287
|
+
SELECT path, slug, description, type, category, title, content, tags, quality, date_captured, project
|
|
288
|
+
FROM mindlore_fts
|
|
289
|
+
WHERE category IN ('cc-subagent', 'cc-session')
|
|
290
|
+
`);
|
|
291
|
+
db.exec(`
|
|
292
|
+
DELETE FROM mindlore_fts WHERE category IN ('cc-subagent', 'cc-session')
|
|
293
|
+
`);
|
|
294
|
+
db.exec("COMMIT");
|
|
295
|
+
} catch (err) {
|
|
296
|
+
db.exec("ROLLBACK");
|
|
297
|
+
throw err;
|
|
298
|
+
}
|
|
299
|
+
const cols = db.pragma("table_info(file_hashes)");
|
|
300
|
+
if (!cols.some((c) => c.name === "table_target")) {
|
|
301
|
+
db.exec("ALTER TABLE file_hashes ADD COLUMN table_target TEXT DEFAULT 'mindlore_fts'");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
];
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// dist/scripts/lib/migrations-v062.js
|
|
310
|
+
var require_migrations_v062 = __commonJS({
|
|
311
|
+
"dist/scripts/lib/migrations-v062.js"(exports2) {
|
|
312
|
+
"use strict";
|
|
313
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
314
|
+
exports2.V062_MIGRATIONS = void 0;
|
|
315
|
+
exports2.V062_MIGRATIONS = [
|
|
316
|
+
{
|
|
317
|
+
version: 8,
|
|
318
|
+
name: "raw_metadata_table",
|
|
319
|
+
up: (db) => {
|
|
320
|
+
db.exec(`
|
|
321
|
+
CREATE TABLE IF NOT EXISTS raw_metadata (
|
|
322
|
+
path TEXT PRIMARY KEY,
|
|
323
|
+
title TEXT,
|
|
324
|
+
url TEXT,
|
|
325
|
+
date_captured TEXT,
|
|
326
|
+
headings TEXT,
|
|
327
|
+
file_size INTEGER,
|
|
328
|
+
line_count INTEGER,
|
|
329
|
+
extracted_at TEXT NOT NULL
|
|
330
|
+
)
|
|
331
|
+
`);
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
version: 9,
|
|
336
|
+
name: "episodes_session_summary",
|
|
337
|
+
up: (db) => {
|
|
338
|
+
const cols = db.pragma("table_info(episodes)");
|
|
339
|
+
if (!cols.some((c) => c.name === "session_summary")) {
|
|
340
|
+
db.exec("ALTER TABLE episodes ADD COLUMN session_summary TEXT");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
];
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// dist/scripts/lib/migrations-v063.js
|
|
349
|
+
var require_migrations_v063 = __commonJS({
|
|
350
|
+
"dist/scripts/lib/migrations-v063.js"(exports2) {
|
|
351
|
+
"use strict";
|
|
352
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
353
|
+
exports2.V063_MIGRATIONS = exports2.SQL_SEARCH_THROTTLE_CREATE = exports2.SQL_SEARCH_CACHE_CREATE = exports2.SQL_VOCABULARY_CREATE = exports2.SQL_FTS_TRIGRAM_CREATE = void 0;
|
|
354
|
+
exports2.SQL_FTS_TRIGRAM_CREATE = "CREATE VIRTUAL TABLE IF NOT EXISTS mindlore_fts_trigram USING fts5(path UNINDEXED, slug, description, type UNINDEXED, category, title, content, tags, quality UNINDEXED, date_captured UNINDEXED, project UNINDEXED, tokenize='trigram')";
|
|
355
|
+
exports2.SQL_VOCABULARY_CREATE = "CREATE TABLE IF NOT EXISTS vocabulary (word TEXT PRIMARY KEY) WITHOUT ROWID";
|
|
356
|
+
exports2.SQL_SEARCH_CACHE_CREATE = "CREATE TABLE IF NOT EXISTS search_cache (query_hash TEXT PRIMARY KEY, results_json TEXT NOT NULL, expires_at TEXT NOT NULL)";
|
|
357
|
+
exports2.SQL_SEARCH_THROTTLE_CREATE = "CREATE TABLE IF NOT EXISTS search_throttle (session_id TEXT PRIMARY KEY, call_count INTEGER NOT NULL DEFAULT 0, last_call TEXT NOT NULL)";
|
|
358
|
+
exports2.V063_MIGRATIONS = [
|
|
359
|
+
{
|
|
360
|
+
version: 10,
|
|
361
|
+
name: "fts_trigram_table",
|
|
362
|
+
up: (db) => {
|
|
363
|
+
db.exec(exports2.SQL_FTS_TRIGRAM_CREATE);
|
|
364
|
+
const porterCount = db.prepare("SELECT COUNT(*) as c FROM mindlore_fts").get().c;
|
|
365
|
+
if (porterCount > 0) {
|
|
366
|
+
db.exec(`
|
|
367
|
+
INSERT INTO mindlore_fts_trigram(path, slug, description, type, category, title, content, tags, quality, date_captured, project)
|
|
368
|
+
SELECT path, slug, description, type, category, title, content, tags, quality, date_captured, project
|
|
369
|
+
FROM mindlore_fts
|
|
370
|
+
`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
version: 11,
|
|
376
|
+
name: "vocabulary_table",
|
|
377
|
+
up: (db) => {
|
|
378
|
+
db.exec(exports2.SQL_VOCABULARY_CREATE);
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
version: 12,
|
|
383
|
+
name: "chunks_table",
|
|
384
|
+
up: (db) => {
|
|
385
|
+
db.exec(`
|
|
386
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
387
|
+
id INTEGER PRIMARY KEY,
|
|
388
|
+
source_path TEXT NOT NULL,
|
|
389
|
+
chunk_index INTEGER NOT NULL,
|
|
390
|
+
heading TEXT,
|
|
391
|
+
breadcrumb TEXT,
|
|
392
|
+
char_count INTEGER,
|
|
393
|
+
UNIQUE(source_path, chunk_index)
|
|
394
|
+
)
|
|
395
|
+
`);
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
version: 13,
|
|
400
|
+
name: "search_cache_tables",
|
|
401
|
+
up: (db) => {
|
|
402
|
+
db.exec(exports2.SQL_SEARCH_CACHE_CREATE);
|
|
403
|
+
db.exec(exports2.SQL_SEARCH_THROTTLE_CREATE);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
];
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// dist/scripts/lib/migrations-v066.js
|
|
411
|
+
var require_migrations_v066 = __commonJS({
|
|
412
|
+
"dist/scripts/lib/migrations-v066.js"(exports2) {
|
|
413
|
+
"use strict";
|
|
414
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
415
|
+
exports2.V066_MIGRATIONS = exports2.SQL_EPISODE_INJECT_LOG_CREATE = void 0;
|
|
416
|
+
exports2.SQL_EPISODE_INJECT_LOG_CREATE = "CREATE TABLE IF NOT EXISTS episode_inject_log (session_id TEXT NOT NULL, episode_id TEXT NOT NULL, injected_at TEXT NOT NULL, PRIMARY KEY (session_id, episode_id))";
|
|
417
|
+
exports2.V066_MIGRATIONS = [
|
|
418
|
+
{
|
|
419
|
+
version: 14,
|
|
420
|
+
name: "episode_inject_log",
|
|
421
|
+
up: (db) => {
|
|
422
|
+
db.exec(exports2.SQL_EPISODE_INJECT_LOG_CREATE);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// dist/scripts/lib/migrations-v067.js
|
|
430
|
+
var require_migrations_v067 = __commonJS({
|
|
431
|
+
"dist/scripts/lib/migrations-v067.js"(exports2) {
|
|
432
|
+
"use strict";
|
|
433
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
434
|
+
exports2.V067_MIGRATIONS = void 0;
|
|
435
|
+
exports2.cleanupExpiredInjectLog = cleanupExpiredInjectLog;
|
|
436
|
+
var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
437
|
+
function cleanupExpiredInjectLog(db, ttlMs = THIRTY_DAYS_MS) {
|
|
438
|
+
const cutoff = new Date(Date.now() - ttlMs).toISOString();
|
|
439
|
+
const result = db.prepare("DELETE FROM episode_inject_log WHERE injected_at < ?").run(cutoff);
|
|
440
|
+
return result.changes;
|
|
441
|
+
}
|
|
442
|
+
exports2.V067_MIGRATIONS = [
|
|
443
|
+
{
|
|
444
|
+
version: 15,
|
|
445
|
+
name: "episodes_graduation_columns",
|
|
446
|
+
up: (db) => {
|
|
447
|
+
db.exec("ALTER TABLE episodes ADD COLUMN graduated_at TEXT");
|
|
448
|
+
db.exec("ALTER TABLE episodes ADD COLUMN rejected_at TEXT");
|
|
449
|
+
db.exec("ALTER TABLE episodes ADD COLUMN rejection_reason TEXT");
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
version: 16,
|
|
454
|
+
name: "episode_inject_log_integer_fix",
|
|
455
|
+
up: (db) => {
|
|
456
|
+
db.exec(`
|
|
457
|
+
CREATE TABLE episode_inject_log_new (
|
|
458
|
+
session_id TEXT NOT NULL,
|
|
459
|
+
episode_id INTEGER NOT NULL,
|
|
460
|
+
injected_at TEXT NOT NULL,
|
|
461
|
+
PRIMARY KEY (session_id, episode_id)
|
|
462
|
+
)
|
|
463
|
+
`);
|
|
464
|
+
db.exec(`
|
|
465
|
+
INSERT INTO episode_inject_log_new (session_id, episode_id, injected_at)
|
|
466
|
+
SELECT session_id, CAST(episode_id AS INTEGER), injected_at
|
|
467
|
+
FROM episode_inject_log
|
|
468
|
+
`);
|
|
469
|
+
db.exec("DROP TABLE episode_inject_log");
|
|
470
|
+
db.exec("ALTER TABLE episode_inject_log_new RENAME TO episode_inject_log");
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
version: 17,
|
|
475
|
+
name: "episode_inject_log_ttl",
|
|
476
|
+
up: (db) => {
|
|
477
|
+
cleanupExpiredInjectLog(db);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
];
|
|
481
|
+
}
|
|
482
|
+
});
|
|
10
483
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
484
|
+
// dist/scripts/lib/migrations-v068.js
|
|
485
|
+
var require_migrations_v068 = __commonJS({
|
|
486
|
+
"dist/scripts/lib/migrations-v068.js"(exports2) {
|
|
487
|
+
"use strict";
|
|
488
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
489
|
+
exports2.V068_MIGRATIONS = void 0;
|
|
490
|
+
exports2.V068_MIGRATIONS = [
|
|
491
|
+
{
|
|
492
|
+
version: 18,
|
|
493
|
+
name: "inject_log_injected_at_index",
|
|
494
|
+
up: (db) => {
|
|
495
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_inject_log_injected_at ON episode_inject_log(injected_at)");
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
version: 19,
|
|
500
|
+
name: "drop_dead_vec_tables",
|
|
501
|
+
up: (db) => {
|
|
502
|
+
const shadowTables = [
|
|
503
|
+
"documents_vec_info",
|
|
504
|
+
"documents_vec_chunks",
|
|
505
|
+
"documents_vec_rowids",
|
|
506
|
+
"documents_vec_vector_chunks00",
|
|
507
|
+
"documents_vec_metadatachunks00",
|
|
508
|
+
"documents_vec_metadatatext00",
|
|
509
|
+
"documents_vec_auxiliary"
|
|
510
|
+
];
|
|
511
|
+
for (const table of shadowTables) {
|
|
512
|
+
db.exec(`DROP TABLE IF EXISTS "${table}"`);
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
db.exec("DROP TABLE IF EXISTS documents_vec");
|
|
516
|
+
} catch {
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
];
|
|
521
|
+
}
|
|
522
|
+
});
|
|
14
523
|
|
|
524
|
+
// dist/scripts/lib/all-migrations.js
|
|
525
|
+
var require_all_migrations = __commonJS({
|
|
526
|
+
"dist/scripts/lib/all-migrations.js"(exports2) {
|
|
527
|
+
"use strict";
|
|
528
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
529
|
+
exports2.EXPECTED_SCHEMA_VERSION = exports2.INIT_MIGRATIONS = exports2.FTS_DB_MIGRATIONS = exports2.ALL_MIGRATIONS = void 0;
|
|
530
|
+
var migrations_js_1 = require_migrations();
|
|
531
|
+
var migrations_v052_js_1 = require_migrations_v052();
|
|
532
|
+
var migrations_v053_js_1 = require_migrations_v053();
|
|
533
|
+
var migrations_v061_js_1 = require_migrations_v061();
|
|
534
|
+
var migrations_v062_js_1 = require_migrations_v062();
|
|
535
|
+
var migrations_v063_js_1 = require_migrations_v063();
|
|
536
|
+
var migrations_v066_js_1 = require_migrations_v066();
|
|
537
|
+
var migrations_v067_js_1 = require_migrations_v067();
|
|
538
|
+
var migrations_v068_js_1 = require_migrations_v068();
|
|
539
|
+
exports2.ALL_MIGRATIONS = [
|
|
540
|
+
...migrations_js_1.V050_MIGRATIONS,
|
|
541
|
+
...migrations_js_1.V051_MIGRATIONS,
|
|
542
|
+
...migrations_v052_js_1.V052_MIGRATIONS,
|
|
543
|
+
...migrations_v053_js_1.V053_MIGRATIONS,
|
|
544
|
+
...migrations_v061_js_1.V061_MIGRATIONS,
|
|
545
|
+
...migrations_v062_js_1.V062_MIGRATIONS,
|
|
546
|
+
...migrations_v063_js_1.V063_MIGRATIONS,
|
|
547
|
+
...migrations_v066_js_1.V066_MIGRATIONS,
|
|
548
|
+
...migrations_v067_js_1.V067_MIGRATIONS,
|
|
549
|
+
...migrations_v068_js_1.V068_MIGRATIONS
|
|
550
|
+
];
|
|
551
|
+
var EPISODES_DEPENDENT = /* @__PURE__ */ new Set([9, 14, 15, 16, 17, 18]);
|
|
552
|
+
exports2.FTS_DB_MIGRATIONS = exports2.ALL_MIGRATIONS.filter((m) => !EPISODES_DEPENDENT.has(m.version));
|
|
553
|
+
exports2.INIT_MIGRATIONS = [
|
|
554
|
+
...migrations_v062_js_1.V062_MIGRATIONS,
|
|
555
|
+
...migrations_v063_js_1.V063_MIGRATIONS,
|
|
556
|
+
...migrations_v066_js_1.V066_MIGRATIONS,
|
|
557
|
+
...migrations_v067_js_1.V067_MIGRATIONS,
|
|
558
|
+
...migrations_v068_js_1.V068_MIGRATIONS
|
|
559
|
+
];
|
|
560
|
+
exports2.EXPECTED_SCHEMA_VERSION = Math.max(...exports2.ALL_MIGRATIONS.map((m) => m.version));
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// hooks/src/mindlore-session-focus.cjs
|
|
565
|
+
var fs = require("fs");
|
|
566
|
+
var path = require("path");
|
|
567
|
+
var { findMindloreDir, readConfig, openDatabase, hasEpisodesTable, querySupersededChains, formatSupersededChains, hookLog, getProjectName, parseFrontmatter, withTelemetry, withTimeoutDb, listSnapshots, isCorruptionError, recoverCorruptDb, getNominationCounts } = require("./lib/mindlore-common.cjs");
|
|
15
568
|
function truncateSection(content, sectionRegex, keepCount, label) {
|
|
16
569
|
const match = content.match(sectionRegex);
|
|
17
570
|
if (!match) return content;
|
|
18
|
-
const lines = match[2].trim().split(
|
|
571
|
+
const lines = match[2].trim().split("\n");
|
|
19
572
|
if (lines.length <= keepCount) return content;
|
|
20
|
-
const kept = lines.slice(0, keepCount).join(
|
|
21
|
-
return content.replace(match[2].trim(), kept +
|
|
573
|
+
const kept = lines.slice(0, keepCount).join("\n");
|
|
574
|
+
return content.replace(match[2].trim(), kept + `
|
|
575
|
+
- ...ve ${lines.length - keepCount} ${label} daha`);
|
|
22
576
|
}
|
|
23
|
-
|
|
24
577
|
function truncateCommits(content) {
|
|
25
|
-
return truncateSection(content, /(## Commits\n)((?:- [^\n]+\n?)+)/, 5,
|
|
578
|
+
return truncateSection(content, /(## Commits\n)((?:- [^\n]+\n?)+)/, 5, "commit");
|
|
26
579
|
}
|
|
27
|
-
|
|
28
580
|
function truncateChangedFiles(content) {
|
|
29
|
-
return truncateSection(content, /(## Changed Files\n)((?:- [^\n]+\n?)+)/, 10,
|
|
581
|
+
return truncateSection(content, /(## Changed Files\n)((?:- [^\n]+\n?)+)/, 10, "dosya");
|
|
30
582
|
}
|
|
31
|
-
|
|
32
583
|
function tryOpenDb(dbPath) {
|
|
33
584
|
return openDatabase(dbPath, { readonly: true });
|
|
34
585
|
}
|
|
35
|
-
|
|
36
586
|
function getEpisodeStats(db, config, project) {
|
|
37
587
|
const chains = querySupersededChains(db, { project, days: 7, limit: 5 });
|
|
38
588
|
let consolidationMsg = null;
|
|
39
589
|
try {
|
|
40
|
-
const rawCount = withTimeoutDb(
|
|
590
|
+
const rawCount = withTimeoutDb(
|
|
591
|
+
db,
|
|
41
592
|
"SELECT COUNT(*) as cnt FROM episodes WHERE consolidation_status = 'raw' OR consolidation_status IS NULL",
|
|
42
|
-
[],
|
|
593
|
+
[],
|
|
594
|
+
{ mode: "get" }
|
|
595
|
+
);
|
|
43
596
|
const cnt = rawCount?.cnt ?? 0;
|
|
44
597
|
const consolThreshold = config?.consolidation?.threshold ?? 50;
|
|
45
598
|
if (cnt >= consolThreshold) {
|
|
46
|
-
consolidationMsg = `[Mindlore] ${cnt} raw episode birikti
|
|
599
|
+
consolidationMsg = `[Mindlore] ${cnt} raw episode birikti \u2014 \`/mindlore-maintain consolidate\` ile birle\u015Ftirmeyi d\xFC\u015F\xFCn.`;
|
|
47
600
|
}
|
|
48
|
-
} catch (_err) {
|
|
601
|
+
} catch (_err) {
|
|
602
|
+
}
|
|
49
603
|
return { chains, consolidationMsg };
|
|
50
604
|
}
|
|
51
|
-
|
|
52
605
|
function checkStaleContent(db) {
|
|
53
606
|
try {
|
|
54
|
-
const thirtyDaysAgo = new Date(Date.now() -
|
|
55
|
-
const row = withTimeoutDb(db,
|
|
607
|
+
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString();
|
|
608
|
+
const row = withTimeoutDb(db, "SELECT COUNT(*) as cnt FROM file_hashes WHERE last_indexed < ?", [thirtyDaysAgo], { mode: "get" });
|
|
56
609
|
const staleCount = row?.cnt ?? 0;
|
|
57
610
|
if (staleCount > 3) {
|
|
58
|
-
return `[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis
|
|
611
|
+
return `[Mindlore: ${staleCount} dosya 30+ gundur guncellenmemis \u2014 \`/mindlore-evolve\` dusun]`;
|
|
59
612
|
}
|
|
60
|
-
} catch (_staleErr) {
|
|
613
|
+
} catch (_staleErr) {
|
|
614
|
+
}
|
|
61
615
|
return null;
|
|
62
616
|
}
|
|
63
|
-
|
|
64
617
|
function loadDbContent({ db, baseDir, config, output, timings, latestDeltaContent, sessionId }) {
|
|
65
618
|
const project = path.basename(process.cwd());
|
|
66
|
-
// Session payload: Session summary, Decisions, Friction, Learnings
|
|
67
619
|
const tPayload = Date.now();
|
|
68
620
|
try {
|
|
69
|
-
const { buildSessionPayload } =
|
|
70
|
-
const payloadBudget = config?.tokenBudget?.sessionInject ??
|
|
621
|
+
const { buildSessionPayload } = require_session_payload();
|
|
622
|
+
const payloadBudget = config?.tokenBudget?.sessionInject ?? 2e3;
|
|
71
623
|
const payload = buildSessionPayload({ db, baseDir, project, tokenBudget: payloadBudget, latestDeltaContent, sessionId });
|
|
72
624
|
for (const section of payload.sections) {
|
|
73
|
-
output.push(`[Mindlore ${section.label}]
|
|
625
|
+
output.push(`[Mindlore ${section.label}]
|
|
626
|
+
${section.content}`);
|
|
74
627
|
}
|
|
75
628
|
} catch (_payloadErr) {
|
|
76
|
-
// Session payload is optional — don't break session start
|
|
77
629
|
}
|
|
78
630
|
timings.db_payload = Date.now() - tPayload;
|
|
79
|
-
|
|
80
|
-
// Supersedes chain display + episode consolidation reminder
|
|
81
631
|
const tSuperseded = Date.now();
|
|
82
632
|
if (hasEpisodesTable(db)) {
|
|
83
633
|
const { chains, consolidationMsg } = getEpisodeStats(db, config, project);
|
|
84
634
|
if (chains.length > 0) {
|
|
85
|
-
output.push(`[Mindlore Supersedes]
|
|
635
|
+
output.push(`[Mindlore Supersedes]
|
|
636
|
+
${formatSupersededChains(chains)}`);
|
|
86
637
|
}
|
|
87
638
|
if (consolidationMsg) {
|
|
88
639
|
output.push(consolidationMsg);
|
|
89
640
|
}
|
|
90
641
|
}
|
|
91
642
|
timings.db_episodes = Date.now() - tSuperseded;
|
|
92
|
-
|
|
93
|
-
// Stale content check
|
|
94
643
|
const tStale = Date.now();
|
|
95
644
|
const staleMsg = checkStaleContent(db);
|
|
96
645
|
if (staleMsg) {
|
|
97
646
|
output.push(staleMsg);
|
|
98
647
|
}
|
|
99
648
|
timings.db_stale = Date.now() - tStale;
|
|
100
|
-
|
|
101
|
-
// Auto reflect trigger (Q1) + Graduated lesson count (Q3)
|
|
102
649
|
try {
|
|
103
650
|
const counts = getNominationCounts(db, project);
|
|
104
651
|
if (counts.staged >= (config?.graduation?.reflectThreshold ?? 5)) {
|
|
105
|
-
output.push(`[Mindlore] ${counts.staged} bekleyen nomination var
|
|
652
|
+
output.push(`[Mindlore] ${counts.staged} bekleyen nomination var \u2014 \`/mindlore-reflect\` \xE7al\u0131\u015Ft\u0131r`);
|
|
106
653
|
}
|
|
107
654
|
if (counts.graduated > 0) {
|
|
108
655
|
output.push(`[Mindlore Graduation] ${counts.graduated} lesson mezun oldu`);
|
|
109
656
|
}
|
|
110
|
-
} catch (_reflectErr) {
|
|
657
|
+
} catch (_reflectErr) {
|
|
658
|
+
}
|
|
111
659
|
}
|
|
112
|
-
|
|
113
660
|
function main() {
|
|
114
661
|
const t0 = Date.now();
|
|
115
662
|
const baseDir = findMindloreDir();
|
|
116
|
-
if (!baseDir) return;
|
|
117
|
-
|
|
118
|
-
// Read session_id from stdin (Claude Code passes { session_id } to SessionStart hooks)
|
|
663
|
+
if (!baseDir) return;
|
|
119
664
|
let sessionId;
|
|
120
665
|
try {
|
|
121
|
-
const stdinData = JSON.parse(fs.readFileSync(0,
|
|
122
|
-
sessionId = stdinData.session_id ||
|
|
123
|
-
} catch {
|
|
124
|
-
|
|
666
|
+
const stdinData = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
|
|
667
|
+
sessionId = stdinData.session_id || void 0;
|
|
668
|
+
} catch {
|
|
669
|
+
sessionId = void 0;
|
|
670
|
+
}
|
|
125
671
|
const output = [];
|
|
126
672
|
const config = readConfig(baseDir);
|
|
127
673
|
const timings = {};
|
|
128
674
|
let sourceChars = 0;
|
|
129
|
-
|
|
130
|
-
// Inject INDEX.md
|
|
131
675
|
const tIndex = Date.now();
|
|
132
|
-
const indexPath = path.join(baseDir,
|
|
676
|
+
const indexPath = path.join(baseDir, "INDEX.md");
|
|
133
677
|
if (fs.existsSync(indexPath)) {
|
|
134
|
-
const content = fs.readFileSync(indexPath,
|
|
678
|
+
const content = fs.readFileSync(indexPath, "utf8").trim();
|
|
135
679
|
sourceChars += content.length;
|
|
136
|
-
output.push(`[Mindlore INDEX]
|
|
680
|
+
output.push(`[Mindlore INDEX]
|
|
681
|
+
${content}`);
|
|
137
682
|
}
|
|
138
683
|
timings.index_read = Date.now() - tIndex;
|
|
139
|
-
|
|
140
|
-
// Inject latest delta + reflect trigger (single readdirSync)
|
|
141
684
|
const tDiary = Date.now();
|
|
142
|
-
const diaryDir = path.join(baseDir,
|
|
143
|
-
let latestDeltaContent =
|
|
685
|
+
const diaryDir = path.join(baseDir, "diary");
|
|
686
|
+
let latestDeltaContent = void 0;
|
|
144
687
|
if (fs.existsSync(diaryDir)) {
|
|
145
688
|
try {
|
|
146
|
-
const diaryFiles = listSnapshots(diaryDir).filter(f => f.startsWith(
|
|
147
|
-
|
|
689
|
+
const diaryFiles = listSnapshots(diaryDir).filter((f) => f.startsWith("delta-"));
|
|
148
690
|
if (diaryFiles.length > 0) {
|
|
149
691
|
const latestName = diaryFiles[diaryFiles.length - 1];
|
|
150
692
|
const latestPath = path.join(diaryDir, latestName);
|
|
151
|
-
const deltaContent = fs.readFileSync(latestPath,
|
|
693
|
+
const deltaContent = fs.readFileSync(latestPath, "utf8").trim();
|
|
152
694
|
sourceChars += deltaContent.length;
|
|
153
695
|
latestDeltaContent = deltaContent;
|
|
154
696
|
const { meta } = parseFrontmatter(deltaContent);
|
|
155
697
|
const deltaProject = meta.project || null;
|
|
156
698
|
const currentProject = getProjectName();
|
|
157
699
|
if (!deltaProject || deltaProject.toLowerCase() === currentProject.toLowerCase()) {
|
|
158
|
-
output.push(`[Mindlore Delta: ${latestName}]
|
|
700
|
+
output.push(`[Mindlore Delta: ${latestName}]
|
|
701
|
+
${truncateChangedFiles(truncateCommits(deltaContent))}`);
|
|
159
702
|
}
|
|
160
703
|
}
|
|
161
|
-
|
|
162
|
-
// Reflect trigger
|
|
163
704
|
const threshold = config?.reflect?.threshold ?? 5;
|
|
164
705
|
if (diaryFiles.length >= threshold) {
|
|
165
|
-
output.push(`[Mindlore] ${diaryFiles.length} diary entry birikti
|
|
706
|
+
output.push(`[Mindlore] ${diaryFiles.length} diary entry birikti \u2014 \`/mindlore-log reflect\` calistirmayi dusun.`);
|
|
166
707
|
}
|
|
167
|
-
} catch (_err) {
|
|
708
|
+
} catch (_err) {
|
|
709
|
+
}
|
|
168
710
|
}
|
|
169
711
|
timings.diary_walk = Date.now() - tDiary;
|
|
170
|
-
|
|
171
|
-
// Version check: compare .version (installed) vs .pkg-version (package)
|
|
172
712
|
const tVersion = Date.now();
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
const pkgVersionPath = path.join(baseDir, '.pkg-version');
|
|
713
|
+
const versionPath = path.join(baseDir, ".version");
|
|
714
|
+
const pkgVersionPath = path.join(baseDir, ".pkg-version");
|
|
176
715
|
try {
|
|
177
716
|
if (fs.existsSync(versionPath) && fs.existsSync(pkgVersionPath)) {
|
|
178
|
-
const installed = fs.readFileSync(versionPath,
|
|
179
|
-
const pkgVersion = fs.readFileSync(pkgVersionPath,
|
|
717
|
+
const installed = fs.readFileSync(versionPath, "utf8").trim();
|
|
718
|
+
const pkgVersion = fs.readFileSync(pkgVersionPath, "utf8").trim();
|
|
180
719
|
if (pkgVersion && pkgVersion !== installed) {
|
|
181
|
-
output.push(`[Mindlore: Guncelleme mevcut (${installed}
|
|
720
|
+
output.push(`[Mindlore: Guncelleme mevcut (${installed} \u2192 ${pkgVersion}). \`npx mindlore init\` calistirin.]`);
|
|
182
721
|
}
|
|
183
722
|
}
|
|
184
|
-
} catch (_err) {
|
|
723
|
+
} catch (_err) {
|
|
724
|
+
}
|
|
185
725
|
timings.version_check = Date.now() - tVersion;
|
|
186
|
-
|
|
187
|
-
// v0.5.4: Consolidated session payload (replaces scattered episodes/activity/alerts injection)
|
|
188
726
|
const tDb = Date.now();
|
|
189
727
|
const outputLenBeforeDb = output.reduce((s, o) => s + o.length, 0);
|
|
190
728
|
try {
|
|
191
|
-
const dbPath = path.join(baseDir,
|
|
729
|
+
const dbPath = path.join(baseDir, "mindlore.db");
|
|
192
730
|
const tDbOpen = Date.now();
|
|
193
731
|
const db = tryOpenDb(dbPath);
|
|
194
732
|
timings.db_open = Date.now() - tDbOpen;
|
|
195
733
|
timings.db_integrity = 0;
|
|
196
|
-
|
|
197
734
|
if (db) {
|
|
198
735
|
try {
|
|
199
|
-
// Schema version check: warn if DB is behind expected version
|
|
200
736
|
const tSchema = Date.now();
|
|
201
737
|
try {
|
|
202
|
-
const { EXPECTED_SCHEMA_VERSION } =
|
|
203
|
-
const row = db.prepare(
|
|
738
|
+
const { EXPECTED_SCHEMA_VERSION } = require_all_migrations();
|
|
739
|
+
const row = db.prepare("SELECT MAX(version) as v FROM schema_versions").get();
|
|
204
740
|
const current = row?.v ?? 0;
|
|
205
741
|
if (current < EXPECTED_SCHEMA_VERSION) {
|
|
206
|
-
output.push(`[Mindlore: schema
|
|
742
|
+
output.push(`[Mindlore: schema g\xFCncel de\u011Fil (v${current} \u2192 v${EXPECTED_SCHEMA_VERSION}). \`npx mindlore upgrade\` \xE7al\u0131\u015Ft\u0131r.]`);
|
|
207
743
|
}
|
|
208
|
-
} catch (_schemaErr) {
|
|
744
|
+
} catch (_schemaErr) {
|
|
745
|
+
}
|
|
209
746
|
timings.schema_check = Date.now() - tSchema;
|
|
210
|
-
|
|
211
747
|
loadDbContent({ db, baseDir, config, output, timings, latestDeltaContent, sessionId });
|
|
212
748
|
} catch (err) {
|
|
213
749
|
if (isCorruptionError(err)) {
|
|
214
|
-
recoverCorruptDb(db, dbPath,
|
|
750
|
+
recoverCorruptDb(db, dbPath, "session-focus");
|
|
215
751
|
}
|
|
216
752
|
} finally {
|
|
217
|
-
try {
|
|
753
|
+
try {
|
|
754
|
+
db.close();
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
218
757
|
}
|
|
219
758
|
}
|
|
220
|
-
} catch (_err) {
|
|
759
|
+
} catch (_err) {
|
|
760
|
+
}
|
|
221
761
|
const outputLenAfterDb = output.reduce((s, o) => s + o.length, 0);
|
|
222
|
-
sourceChars +=
|
|
762
|
+
sourceChars += outputLenAfterDb - outputLenBeforeDb;
|
|
223
763
|
timings.db_total = Date.now() - tDb;
|
|
224
|
-
|
|
225
764
|
timings.total = Date.now() - t0;
|
|
226
|
-
hookLog(
|
|
227
|
-
|
|
228
|
-
// Token budget for session inject
|
|
229
|
-
// Defaults match DEFAULT_TOKEN_BUDGET in scripts/lib/constants.ts
|
|
765
|
+
hookLog("session-focus", "info", `timings: ${JSON.stringify(timings)}`);
|
|
230
766
|
const budgetConfig = config?.tokenBudget ?? {};
|
|
231
|
-
const maxInjectChars = (budgetConfig.sessionInject ||
|
|
232
|
-
|
|
233
|
-
let joined = output.join('\n\n');
|
|
767
|
+
const maxInjectChars = (budgetConfig.sessionInject || 2e3) * 4;
|
|
768
|
+
let joined = output.join("\n\n");
|
|
234
769
|
if (joined.length > maxInjectChars) {
|
|
235
|
-
joined = joined.slice(0, maxInjectChars) +
|
|
770
|
+
joined = joined.slice(0, maxInjectChars) + "\n[...truncated by token budget]";
|
|
236
771
|
}
|
|
237
|
-
|
|
238
|
-
// v0.6.1: Daemon auto-start removed (daemon deprecated — MCP Server in v0.7)
|
|
239
|
-
|
|
240
772
|
if (joined.length > 0) {
|
|
241
|
-
process.stdout.write(joined +
|
|
773
|
+
process.stdout.write(joined + "\n");
|
|
242
774
|
}
|
|
243
|
-
|
|
244
775
|
const inject_tokens = Math.ceil(joined.length / 4);
|
|
245
776
|
const source_tokens = Math.ceil(sourceChars / 4);
|
|
246
777
|
return { inject_tokens, source_tokens };
|
|
247
778
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
hookLog('mindlore-session-focus', 'error', err?.message ?? String(err));
|
|
779
|
+
withTelemetry("mindlore-session-focus", main).catch((err) => {
|
|
780
|
+
hookLog("mindlore-session-focus", "error", err?.message ?? String(err));
|
|
251
781
|
process.exit(0);
|
|
252
782
|
});
|
|
253
|
-
|
|
254
|
-
if (typeof module !== 'undefined') {
|
|
783
|
+
if (typeof module !== "undefined") {
|
|
255
784
|
module.exports = { truncateCommits, truncateChangedFiles, getEpisodeStats, checkStaleContent };
|
|
256
785
|
}
|