apsolut-cortex 0.1.2 → 0.2.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/dist/cli.js +35 -229
- package/dist/hooks/post-tool-use.js +6 -4
- package/dist/hooks/session-end.js +9 -18
- package/dist/hooks/session-start.js +7 -5
- package/dist/hooks/stop.js +7 -5
- package/dist/mcp/server.js +5 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,43 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import {
|
|
5
|
+
existsSync as existsSync3,
|
|
6
|
+
mkdirSync as mkdirSync3,
|
|
7
|
+
readFileSync as readFileSync2,
|
|
8
|
+
writeFileSync as writeFileSync2
|
|
9
|
+
} from "fs";
|
|
10
|
+
import { join as join2, resolve, dirname as dirname2 } from "path";
|
|
11
|
+
import { homedir as homedir2 } from "os";
|
|
12
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
13
|
+
|
|
14
|
+
// src/registry.ts
|
|
15
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
16
|
+
import { dirname } from "path";
|
|
13
17
|
|
|
14
18
|
// src/db.ts
|
|
15
|
-
var exports_db = {};
|
|
16
|
-
__export(exports_db, {
|
|
17
|
-
upsertSession: () => upsertSession,
|
|
18
|
-
upsertProject: () => upsertProject,
|
|
19
|
-
updateWeight: () => updateWeight,
|
|
20
|
-
searchVector: () => searchVector,
|
|
21
|
-
searchBM25: () => searchBM25,
|
|
22
|
-
mergeRRF: () => mergeRRF,
|
|
23
|
-
markObservationsPromoted: () => markObservationsPromoted,
|
|
24
|
-
insertObservation: () => insertObservation,
|
|
25
|
-
insertMemory: () => insertMemory,
|
|
26
|
-
getSessionObservations: () => getSessionObservations,
|
|
27
|
-
getRecentSummaries: () => getRecentSummaries,
|
|
28
|
-
getDb: () => getDb,
|
|
29
|
-
decayAndPrune: () => decayAndPrune,
|
|
30
|
-
cosineSimilarity: () => cosineSimilarity,
|
|
31
|
-
applyMMR: () => applyMMR,
|
|
32
|
-
REGISTRY_PATH: () => REGISTRY_PATH,
|
|
33
|
-
MODELS_DIR: () => MODELS_DIR,
|
|
34
|
-
DB_PATH: () => DB_PATH,
|
|
35
|
-
CORTEX_DIR: () => CORTEX_DIR
|
|
36
|
-
});
|
|
37
19
|
import Database from "better-sqlite3";
|
|
38
20
|
import { existsSync, mkdirSync } from "fs";
|
|
39
21
|
import { homedir } from "os";
|
|
40
22
|
import { join } from "path";
|
|
23
|
+
var CORTEX_DIR = join(homedir(), ".apsolut");
|
|
24
|
+
var DB_PATH = join(CORTEX_DIR, "memory.db");
|
|
25
|
+
var REGISTRY_PATH = join(CORTEX_DIR, "registry.json");
|
|
26
|
+
var MODELS_DIR = join(CORTEX_DIR, "models");
|
|
27
|
+
var _db = null;
|
|
41
28
|
function getDb() {
|
|
42
29
|
if (_db)
|
|
43
30
|
return _db;
|
|
@@ -139,195 +126,8 @@ function getDb() {
|
|
|
139
126
|
`);
|
|
140
127
|
return _db;
|
|
141
128
|
}
|
|
142
|
-
function upsertProject(db, project) {
|
|
143
|
-
const existing = db.prepare("SELECT id FROM projects WHERE id = ?").get(project.id);
|
|
144
|
-
if (existing) {
|
|
145
|
-
db.prepare("UPDATE projects SET last_session = ? WHERE id = ?").run(Date.now(), project.id);
|
|
146
|
-
} else {
|
|
147
|
-
db.prepare("INSERT INTO projects (id, name, path, created_at) VALUES (?, ?, ?, ?)").run(project.id, project.name, project.path ?? null, Date.now());
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
function upsertSession(db, s) {
|
|
151
|
-
const existing = db.prepare("SELECT id FROM sessions WHERE id = ?").get(s.id);
|
|
152
|
-
if (existing) {
|
|
153
|
-
const sets = [];
|
|
154
|
-
const vals = [];
|
|
155
|
-
if (s.ended_at !== undefined) {
|
|
156
|
-
sets.push("ended_at = ?");
|
|
157
|
-
vals.push(s.ended_at);
|
|
158
|
-
}
|
|
159
|
-
if (s.summary !== undefined) {
|
|
160
|
-
sets.push("summary = ?");
|
|
161
|
-
vals.push(s.summary);
|
|
162
|
-
}
|
|
163
|
-
if (s.memories_stored !== undefined) {
|
|
164
|
-
sets.push("memories_stored = ?");
|
|
165
|
-
vals.push(s.memories_stored);
|
|
166
|
-
}
|
|
167
|
-
if (s.tool_failures !== undefined) {
|
|
168
|
-
sets.push("tool_failures = ?");
|
|
169
|
-
vals.push(s.tool_failures);
|
|
170
|
-
}
|
|
171
|
-
if (sets.length) {
|
|
172
|
-
vals.push(s.id);
|
|
173
|
-
db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = ?`).run(...vals);
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
db.prepare("INSERT INTO sessions (id, project_id, started_at) VALUES (?, ?, ?)").run(s.id, s.project_id, Date.now());
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function getRecentSummaries(db, projectId, limit = 3) {
|
|
180
|
-
const rows = db.prepare(`
|
|
181
|
-
SELECT summary FROM sessions
|
|
182
|
-
WHERE project_id = ? AND summary IS NOT NULL AND summary != ''
|
|
183
|
-
ORDER BY started_at DESC LIMIT ?
|
|
184
|
-
`).all(projectId, limit);
|
|
185
|
-
return rows.map((r) => r.summary);
|
|
186
|
-
}
|
|
187
|
-
function insertObservation(db, obs) {
|
|
188
|
-
db.prepare(`
|
|
189
|
-
INSERT INTO observations (id, session_id, project_id, tool_name, content, category, created_at)
|
|
190
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
191
|
-
`).run(crypto.randomUUID(), obs.session_id, obs.project_id, obs.tool_name ?? null, obs.content, obs.category ?? null, Date.now());
|
|
192
|
-
}
|
|
193
|
-
function getSessionObservations(db, sessionId) {
|
|
194
|
-
return db.prepare("SELECT tool_name, content, category FROM observations WHERE session_id = ? AND promoted = 0 ORDER BY created_at ASC").all(sessionId);
|
|
195
|
-
}
|
|
196
|
-
function markObservationsPromoted(db, sessionId) {
|
|
197
|
-
db.prepare("UPDATE observations SET promoted = 1 WHERE session_id = ?").run(sessionId);
|
|
198
|
-
}
|
|
199
|
-
function insertMemory(db, m) {
|
|
200
|
-
const id = crypto.randomUUID();
|
|
201
|
-
db.prepare(`
|
|
202
|
-
INSERT INTO memories
|
|
203
|
-
(id, project_id, tier, category, trust, content, context,
|
|
204
|
-
source, embedding, weight, used_count, created_at, session_id)
|
|
205
|
-
VALUES
|
|
206
|
-
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
207
|
-
`).run(id, m.project_id, m.tier, m.category, m.trust, m.content, m.context ?? null, m.source, m.embedding ?? null, m.weight, Date.now(), m.session_id ?? null);
|
|
208
|
-
return id;
|
|
209
|
-
}
|
|
210
|
-
function searchBM25(db, projectId, query, limit) {
|
|
211
|
-
return db.prepare(`
|
|
212
|
-
SELECT m.* FROM memories_fts
|
|
213
|
-
JOIN memories m ON m.rowid = memories_fts.rowid
|
|
214
|
-
WHERE memories_fts MATCH ? AND m.project_id = ?
|
|
215
|
-
ORDER BY bm25(memories_fts) LIMIT ?
|
|
216
|
-
`).all(query, projectId, limit);
|
|
217
|
-
}
|
|
218
|
-
function cosineSimilarity(a, b) {
|
|
219
|
-
let dot = 0, na = 0, nb = 0;
|
|
220
|
-
for (let i = 0;i < a.length; i++) {
|
|
221
|
-
dot += a[i] * b[i];
|
|
222
|
-
na += a[i] * a[i];
|
|
223
|
-
nb += b[i] * b[i];
|
|
224
|
-
}
|
|
225
|
-
const d = Math.sqrt(na) * Math.sqrt(nb);
|
|
226
|
-
return d === 0 ? 0 : dot / d;
|
|
227
|
-
}
|
|
228
|
-
function searchVector(db, projectId, queryEmb, limit) {
|
|
229
|
-
const candidates = db.prepare("SELECT * FROM memories WHERE project_id = ? AND embedding IS NOT NULL").all(projectId);
|
|
230
|
-
return candidates.map((m) => ({
|
|
231
|
-
...m,
|
|
232
|
-
similarity: cosineSimilarity(queryEmb, new Float32Array(m.embedding.buffer))
|
|
233
|
-
})).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
234
|
-
}
|
|
235
|
-
function mergeRRF(list1, list2, limit, allItems) {
|
|
236
|
-
const k = 60;
|
|
237
|
-
const scores = new Map;
|
|
238
|
-
list1.forEach((r, i) => scores.set(r.id, (scores.get(r.id) ?? 0) + 1 / (i + k)));
|
|
239
|
-
list2.forEach((r, i) => scores.set(r.id, (scores.get(r.id) ?? 0) + 1 / (i + k)));
|
|
240
|
-
return [...scores.entries()].sort(([, a], [, b]) => b - a).slice(0, limit).map(([id]) => allItems.get(id)).filter(Boolean);
|
|
241
|
-
}
|
|
242
|
-
function applyMMR(candidates, queryEmb, limit, lambda = 0.7) {
|
|
243
|
-
if (!queryEmb || candidates.length <= limit)
|
|
244
|
-
return candidates.slice(0, limit);
|
|
245
|
-
const selected = [];
|
|
246
|
-
const remaining = [...candidates];
|
|
247
|
-
while (selected.length < limit && remaining.length > 0) {
|
|
248
|
-
let bestIdx = 0;
|
|
249
|
-
let bestScore = -Infinity;
|
|
250
|
-
for (let i = 0;i < remaining.length; i++) {
|
|
251
|
-
const cand = remaining[i];
|
|
252
|
-
const candEmb = cand.embedding ? new Float32Array(cand.embedding.buffer) : null;
|
|
253
|
-
if (!candEmb) {
|
|
254
|
-
bestIdx = i;
|
|
255
|
-
break;
|
|
256
|
-
}
|
|
257
|
-
const relevance = cand.similarity ?? cosineSimilarity(queryEmb, candEmb);
|
|
258
|
-
const maxSim = selected.reduce((max, s) => {
|
|
259
|
-
if (!s.embedding)
|
|
260
|
-
return max;
|
|
261
|
-
const sim = cosineSimilarity(candEmb, new Float32Array(s.embedding.buffer));
|
|
262
|
-
return Math.max(max, sim);
|
|
263
|
-
}, 0);
|
|
264
|
-
const score = lambda * relevance - (1 - lambda) * maxSim;
|
|
265
|
-
if (score > bestScore) {
|
|
266
|
-
bestScore = score;
|
|
267
|
-
bestIdx = i;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
selected.push(remaining[bestIdx]);
|
|
271
|
-
remaining.splice(bestIdx, 1);
|
|
272
|
-
}
|
|
273
|
-
return selected;
|
|
274
|
-
}
|
|
275
|
-
function updateWeight(db, id, score) {
|
|
276
|
-
const mem = db.prepare("SELECT weight, used_count FROM memories WHERE id = ?").get(id);
|
|
277
|
-
if (!mem)
|
|
278
|
-
return;
|
|
279
|
-
const alpha = 0.3;
|
|
280
|
-
const newWeight = alpha * (score / 3) + (1 - alpha) * mem.weight;
|
|
281
|
-
const newTrust = newWeight > 1.4 || mem.used_count + 1 >= 3 ? "validated" : undefined;
|
|
282
|
-
if (newTrust) {
|
|
283
|
-
db.prepare("UPDATE memories SET weight = ?, used_count = used_count + 1, last_used = ?, trust = CASE WHEN trust = 'observed' THEN ? ELSE trust END WHERE id = ?").run(newWeight, Date.now(), newTrust, id);
|
|
284
|
-
} else {
|
|
285
|
-
db.prepare("UPDATE memories SET weight = ?, used_count = used_count + 1, last_used = ? WHERE id = ?").run(newWeight, Date.now(), id);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
function decayAndPrune(db, projectId) {
|
|
289
|
-
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
|
290
|
-
const decayed = db.prepare(`
|
|
291
|
-
UPDATE memories
|
|
292
|
-
SET weight = weight * CASE
|
|
293
|
-
WHEN trust IN ('proven', 'canonical') THEN 1.0
|
|
294
|
-
WHEN trust = 'validated' THEN 0.98
|
|
295
|
-
ELSE 0.95
|
|
296
|
-
END
|
|
297
|
-
WHERE project_id = ?
|
|
298
|
-
AND trust NOT IN ('canonical')
|
|
299
|
-
AND (last_used IS NULL OR last_used < ?)
|
|
300
|
-
`).run(projectId, cutoff).changes;
|
|
301
|
-
const pruned = db.prepare(`
|
|
302
|
-
DELETE FROM memories
|
|
303
|
-
WHERE project_id = ? AND weight < 0.1 AND used_count > 3
|
|
304
|
-
AND trust NOT IN ('proven', 'canonical')
|
|
305
|
-
`).run(projectId).changes;
|
|
306
|
-
return { decayed, pruned };
|
|
307
|
-
}
|
|
308
|
-
var CORTEX_DIR, DB_PATH, REGISTRY_PATH, MODELS_DIR, _db = null;
|
|
309
|
-
var init_db = __esm(() => {
|
|
310
|
-
CORTEX_DIR = join(homedir(), ".apsolut");
|
|
311
|
-
DB_PATH = join(CORTEX_DIR, "memory.db");
|
|
312
|
-
REGISTRY_PATH = join(CORTEX_DIR, "registry.json");
|
|
313
|
-
MODELS_DIR = join(CORTEX_DIR, "models");
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
// src/cli.ts
|
|
317
|
-
import {
|
|
318
|
-
existsSync as existsSync3,
|
|
319
|
-
mkdirSync as mkdirSync3,
|
|
320
|
-
readFileSync as readFileSync2,
|
|
321
|
-
writeFileSync as writeFileSync2
|
|
322
|
-
} from "fs";
|
|
323
|
-
import { join as join2, resolve, dirname as dirname2 } from "path";
|
|
324
|
-
import { homedir as homedir2 } from "os";
|
|
325
|
-
import { fileURLToPath } from "url";
|
|
326
129
|
|
|
327
130
|
// src/registry.ts
|
|
328
|
-
init_db();
|
|
329
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
330
|
-
import { dirname } from "path";
|
|
331
131
|
function readRegistry() {
|
|
332
132
|
if (!existsSync2(REGISTRY_PATH))
|
|
333
133
|
return { projects: {} };
|
|
@@ -403,7 +203,7 @@ async function runHook(name) {
|
|
|
403
203
|
`);
|
|
404
204
|
process.exit(0);
|
|
405
205
|
}
|
|
406
|
-
await import(hookPath);
|
|
206
|
+
await import(pathToFileURL(hookPath).href);
|
|
407
207
|
}
|
|
408
208
|
async function init() {
|
|
409
209
|
console.log(`
|
|
@@ -453,10 +253,10 @@ apsolut-cortex init
|
|
|
453
253
|
console.log(`✓ Written .mcp.json`);
|
|
454
254
|
const hookCmd = IS_DIST ? "apsolut-cortex" : `bun run ${join2(__dirname2, "cli.ts")}`;
|
|
455
255
|
const hookEntries = {
|
|
456
|
-
SessionStart: [{ command: `${hookCmd} hook:session-start` }],
|
|
457
|
-
PostToolUse: [{ command: `${hookCmd} hook:post-tool-use` }],
|
|
458
|
-
Stop: [{ command: `${hookCmd} hook:stop` }],
|
|
459
|
-
SessionEnd: [{ command: `${hookCmd} hook:session-end` }]
|
|
256
|
+
SessionStart: [{ matcher: "", hooks: [{ type: "command", command: `${hookCmd} hook:session-start` }] }],
|
|
257
|
+
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: `${hookCmd} hook:post-tool-use` }] }],
|
|
258
|
+
Stop: [{ matcher: "", hooks: [{ type: "command", command: `${hookCmd} hook:stop` }] }],
|
|
259
|
+
SessionEnd: [{ matcher: "", hooks: [{ type: "command", command: `${hookCmd} hook:session-end` }] }]
|
|
460
260
|
};
|
|
461
261
|
let settings = {};
|
|
462
262
|
const settingsDir = dirname2(CLAUDE_SETTINGS);
|
|
@@ -501,7 +301,7 @@ apsolut-cortex init
|
|
|
501
301
|
│ ██║ ██║██║ ███████║╚██████╔╝███████╗╚██████╔╝ ██║ │
|
|
502
302
|
│ ╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ │
|
|
503
303
|
│ │
|
|
504
|
-
│ c o r t e x · v
|
|
304
|
+
│ c o r t e x · v ${PKG_VERSION} │
|
|
505
305
|
│ │
|
|
506
306
|
└─────────────────────────────────────────────────────────┘
|
|
507
307
|
|
|
@@ -519,13 +319,12 @@ apsolut-cortex init
|
|
|
519
319
|
console.log(BANNER);
|
|
520
320
|
}
|
|
521
321
|
async function status() {
|
|
522
|
-
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_db(), exports_db));
|
|
523
322
|
if (!existsSync3(PROJECT_CONFIG)) {
|
|
524
323
|
console.log("No project found. Run: apsolut-cortex init");
|
|
525
324
|
process.exit(1);
|
|
526
325
|
}
|
|
527
326
|
const project = JSON.parse(readFileSync2(PROJECT_CONFIG, "utf-8"));
|
|
528
|
-
const db =
|
|
327
|
+
const db = getDb();
|
|
529
328
|
const total = db.prepare("SELECT COUNT(*) as n FROM memories WHERE project_id = ?").get(project.id).n;
|
|
530
329
|
const sessions = db.prepare("SELECT COUNT(*) as n FROM sessions WHERE project_id = ?").get(project.id).n;
|
|
531
330
|
const byTrust = db.prepare(`
|
|
@@ -572,7 +371,14 @@ function uninstall() {
|
|
|
572
371
|
if (hooks) {
|
|
573
372
|
for (const event of ["SessionStart", "PostToolUse", "Stop", "SessionEnd"]) {
|
|
574
373
|
if (hooks[event]) {
|
|
575
|
-
hooks[event] = hooks[event].filter((e) =>
|
|
374
|
+
hooks[event] = hooks[event].filter((e) => {
|
|
375
|
+
if (typeof e !== "object")
|
|
376
|
+
return true;
|
|
377
|
+
if (Array.isArray(e.hooks)) {
|
|
378
|
+
return !e.hooks.some((h) => h.command?.includes("apsolut-cortex"));
|
|
379
|
+
}
|
|
380
|
+
return !e.command?.includes("apsolut-cortex");
|
|
381
|
+
});
|
|
576
382
|
}
|
|
577
383
|
}
|
|
578
384
|
writeFileSync2(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
|
|
4
1
|
// src/hooks/post-tool-use.ts
|
|
5
2
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
6
3
|
import { join as join2 } from "path";
|
|
@@ -190,7 +187,12 @@ function classifyToolUse(toolName, toolInput, toolResponse) {
|
|
|
190
187
|
|
|
191
188
|
// src/hooks/post-tool-use.ts
|
|
192
189
|
async function main() {
|
|
193
|
-
const raw = await
|
|
190
|
+
const raw = await new Promise((resolve) => {
|
|
191
|
+
let d = "";
|
|
192
|
+
process.stdin.setEncoding("utf-8");
|
|
193
|
+
process.stdin.on("data", (c) => d += c);
|
|
194
|
+
process.stdin.on("end", () => resolve(d));
|
|
195
|
+
});
|
|
194
196
|
let data = {};
|
|
195
197
|
try {
|
|
196
198
|
data = JSON.parse(raw);
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
|
|
4
1
|
// src/hooks/session-end.ts
|
|
5
2
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
6
|
-
import { join as
|
|
3
|
+
import { join as join2 } from "path";
|
|
7
4
|
|
|
8
5
|
// src/db.ts
|
|
9
6
|
import Database from "better-sqlite3";
|
|
@@ -324,18 +321,7 @@ async function compressSession(observations, project) {
|
|
|
324
321
|
|
|
325
322
|
// src/embed.ts
|
|
326
323
|
import { pipeline, env } from "@xenova/transformers";
|
|
327
|
-
|
|
328
|
-
// src/db.ts
|
|
329
|
-
import Database2 from "better-sqlite3";
|
|
330
|
-
import { homedir as homedir2 } from "os";
|
|
331
|
-
import { join as join2 } from "path";
|
|
332
|
-
var CORTEX_DIR2 = join2(homedir2(), ".apsolut");
|
|
333
|
-
var DB_PATH2 = join2(CORTEX_DIR2, "memory.db");
|
|
334
|
-
var REGISTRY_PATH2 = join2(CORTEX_DIR2, "registry.json");
|
|
335
|
-
var MODELS_DIR2 = join2(CORTEX_DIR2, "models");
|
|
336
|
-
|
|
337
|
-
// src/embed.ts
|
|
338
|
-
env.cacheDir = MODELS_DIR2;
|
|
324
|
+
env.cacheDir = MODELS_DIR;
|
|
339
325
|
env.allowRemoteModels = true;
|
|
340
326
|
var _embedder = null;
|
|
341
327
|
async function getEmbedder() {
|
|
@@ -355,7 +341,12 @@ function float32ToBuffer(arr) {
|
|
|
355
341
|
|
|
356
342
|
// src/hooks/session-end.ts
|
|
357
343
|
async function main() {
|
|
358
|
-
const raw = await
|
|
344
|
+
const raw = await new Promise((resolve) => {
|
|
345
|
+
let d = "";
|
|
346
|
+
process.stdin.setEncoding("utf-8");
|
|
347
|
+
process.stdin.on("data", (c) => d += c);
|
|
348
|
+
process.stdin.on("end", () => resolve(d));
|
|
349
|
+
});
|
|
359
350
|
let data = {};
|
|
360
351
|
try {
|
|
361
352
|
data = JSON.parse(raw);
|
|
@@ -364,7 +355,7 @@ async function main() {
|
|
|
364
355
|
}
|
|
365
356
|
const cwd = data.cwd ?? process.cwd();
|
|
366
357
|
const sessionId = data.session_id ?? "unknown";
|
|
367
|
-
const projectFile =
|
|
358
|
+
const projectFile = join2(cwd, ".apsolut", "project.json");
|
|
368
359
|
if (!existsSync2(projectFile))
|
|
369
360
|
process.exit(0);
|
|
370
361
|
let project = null;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
|
|
4
1
|
// src/hooks/session-start.ts
|
|
5
2
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
6
3
|
import { join as join2 } from "path";
|
|
@@ -156,7 +153,12 @@ function upsertSession(db, s) {
|
|
|
156
153
|
|
|
157
154
|
// src/hooks/session-start.ts
|
|
158
155
|
async function main() {
|
|
159
|
-
const raw = await
|
|
156
|
+
const raw = await new Promise((resolve) => {
|
|
157
|
+
let d = "";
|
|
158
|
+
process.stdin.setEncoding("utf-8");
|
|
159
|
+
process.stdin.on("data", (c) => d += c);
|
|
160
|
+
process.stdin.on("end", () => resolve(d));
|
|
161
|
+
});
|
|
160
162
|
let data = {};
|
|
161
163
|
try {
|
|
162
164
|
data = JSON.parse(raw);
|
|
@@ -180,7 +182,7 @@ async function main() {
|
|
|
180
182
|
const db = getDb();
|
|
181
183
|
upsertProject(db, { id: project.id, name: project.name, path: cwd });
|
|
182
184
|
upsertSession(db, { id: sessionId, project_id: project.id });
|
|
183
|
-
process.stdout.write(`[apsolut-cortex] Project: ${project.name}
|
|
185
|
+
process.stdout.write(`[apsolut-cortex] Project: ${project.name} — say "remember <topic>" to search memory.`);
|
|
184
186
|
} catch {
|
|
185
187
|
process.exit(0);
|
|
186
188
|
}
|
package/dist/hooks/stop.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
|
|
4
1
|
// src/hooks/stop.ts
|
|
5
2
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
6
3
|
import { join as join2 } from "path";
|
|
@@ -158,7 +155,7 @@ var CORRECTION_PATTERNS = [
|
|
|
158
155
|
/(?:my mistake|i was wrong|incorrect)[^.]*[.!]\s*(.{20,150})/gi,
|
|
159
156
|
/(?:wait|oops)[,.]?\s+(.{20,150})/gi,
|
|
160
157
|
/(?:turns? out|it seems?)\s+(.{20,150})/gi,
|
|
161
|
-
/(?:should(?:n'?t)? have|shouldn'?t).{0,30}[
|
|
158
|
+
/(?:should(?:n'?t)? have|shouldn'?t).{0,30}[—–-]\s*(.{20,150})/gi,
|
|
162
159
|
/(?:the correct|correct(?:ly)?)\s+(?:way|path|file|approach)\s+is\s+(.{20,150})/gi
|
|
163
160
|
];
|
|
164
161
|
function extractCorrections(transcript) {
|
|
@@ -175,7 +172,12 @@ function extractCorrections(transcript) {
|
|
|
175
172
|
return [...new Set(found)].slice(0, 5);
|
|
176
173
|
}
|
|
177
174
|
async function main() {
|
|
178
|
-
const raw = await
|
|
175
|
+
const raw = await new Promise((resolve) => {
|
|
176
|
+
let d = "";
|
|
177
|
+
process.stdin.setEncoding("utf-8");
|
|
178
|
+
process.stdin.on("data", (c) => d += c);
|
|
179
|
+
process.stdin.on("end", () => resolve(d));
|
|
180
|
+
});
|
|
179
181
|
let data = {};
|
|
180
182
|
try {
|
|
181
183
|
data = JSON.parse(raw);
|
package/dist/mcp/server.js
CHANGED
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
ListToolsRequestSchema
|
|
10
10
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
11
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
12
|
-
import { join as join3 } from "path";
|
|
12
|
+
import { join as join3, dirname, resolve } from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
13
14
|
|
|
14
15
|
// src/db.ts
|
|
15
16
|
import Database from "better-sqlite3";
|
|
@@ -264,7 +265,9 @@ var db = getDb();
|
|
|
264
265
|
if (project?.id) {
|
|
265
266
|
upsertProject(db, { id: project.id, name: project.name, path: PROJECT_PATH });
|
|
266
267
|
}
|
|
267
|
-
var
|
|
268
|
+
var __mcp_dirname = dirname(fileURLToPath(import.meta.url));
|
|
269
|
+
var PKG_VERSION = JSON.parse(readFileSync(resolve(__mcp_dirname, "..", "package.json"), "utf-8")).version;
|
|
270
|
+
var server = new Server({ name: "apsolut-cortex", version: PKG_VERSION }, { capabilities: { tools: {} } });
|
|
268
271
|
function requireProject() {
|
|
269
272
|
if (!project?.id)
|
|
270
273
|
throw new Error("No project found. Run: apsolut-cortex init");
|