@alaarab/cortex 1.13.6 → 1.14.0
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 +16 -15
- package/mcp/dist/cli-config.js +20 -15
- package/mcp/dist/cli-extract.js +15 -10
- package/mcp/dist/cli-govern.js +37 -32
- package/mcp/dist/cli-hooks-session.js +46 -41
- package/mcp/dist/cli-hooks.js +24 -19
- package/mcp/dist/cli.js +26 -21
- package/mcp/dist/data-access.js +7 -43
- package/mcp/dist/index.js +15 -15
- package/mcp/dist/link-skills.js +0 -6
- package/mcp/dist/mcp-finding.js +2 -2
- package/mcp/dist/mcp-search.js +4 -4
- package/mcp/dist/shared-index.js +45 -26
- package/mcp/dist/shared.js +6 -0
- package/package.json +2 -2
- package/starter/README.md +2 -2
package/mcp/dist/mcp-search.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as fs from "fs";
|
|
|
4
4
|
import { isValidProjectName, buildRobustFtsQuery } from "./utils.js";
|
|
5
5
|
import { keywordFallbackSearch } from "./core-search.js";
|
|
6
6
|
import { readFindings } from "./data-access.js";
|
|
7
|
-
import { debugLog, runtimeFile, } from "./shared.js";
|
|
7
|
+
import { debugLog, runtimeFile, DOC_TYPES, FINDING_TAGS, } from "./shared.js";
|
|
8
8
|
import { queryRows, cosineFallback, queryEntityLinks, extractSnippet, queryDocBySourceKey, } from "./shared-index.js";
|
|
9
9
|
import { runCustomHooks } from "./hooks.js";
|
|
10
10
|
import { entryScoreKey, getQualityMultiplier } from "./shared-governance.js";
|
|
@@ -72,10 +72,10 @@ export function register(server, ctx) {
|
|
|
72
72
|
query: z.string().describe("Search query (supports FTS5 syntax: AND, OR, NOT, phrase matching with quotes)"),
|
|
73
73
|
limit: z.number().min(1).max(20).optional().describe("Max results to return (1-20, default 5)"),
|
|
74
74
|
project: z.string().optional().describe("Filter by project name."),
|
|
75
|
-
type: z.enum(
|
|
75
|
+
type: z.enum(DOC_TYPES)
|
|
76
76
|
.optional()
|
|
77
77
|
.describe("Filter by document type: claude, findings, reference, summary, backlog, skill"),
|
|
78
|
-
tag: z.enum(
|
|
78
|
+
tag: z.enum(FINDING_TAGS)
|
|
79
79
|
.optional()
|
|
80
80
|
.describe("Filter findings by type tag (decision, pitfall, pattern are canonical; tradeoff, architecture, bug are legacy aliases)."),
|
|
81
81
|
since: z.string().optional().describe('Filter findings by creation date. Formats: "7d" (last 7 days), "30d" (last 30 days), "YYYY-MM" (since start of month), "YYYY-MM-DD" (since date).'),
|
|
@@ -277,8 +277,8 @@ export function register(server, ctx) {
|
|
|
277
277
|
boost = 1.2;
|
|
278
278
|
}
|
|
279
279
|
catch { /* file may not exist on disk */ }
|
|
280
|
+
const scoreKey = entryScoreKey(rowProject, filename, content);
|
|
280
281
|
const snippet = extractSnippet(content, query);
|
|
281
|
-
const scoreKey = entryScoreKey(rowProject, filename, snippet);
|
|
282
282
|
boost *= getQualityMultiplier(cortexPath, scoreKey);
|
|
283
283
|
return { row, rank: (rows.length - idx) * boost };
|
|
284
284
|
});
|
package/mcp/dist/shared-index.js
CHANGED
|
@@ -107,32 +107,43 @@ function touchSentinel(cortexPath) {
|
|
|
107
107
|
}
|
|
108
108
|
catch { /* best-effort */ }
|
|
109
109
|
}
|
|
110
|
-
function computeCortexHash(cortexPath, profile) {
|
|
111
|
-
const projectDirs = getProjectDirs(cortexPath, profile);
|
|
110
|
+
function computeCortexHash(cortexPath, profile, preGlobbed) {
|
|
112
111
|
const policy = getIndexPolicy(cortexPath);
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const mdFiles = globSync(pattern, { cwd: dir, nodir: true, dot, ignore: policy.excludeGlobs });
|
|
120
|
-
for (const f of mdFiles)
|
|
121
|
-
matched.add(f);
|
|
112
|
+
const hash = crypto.createHash("sha1");
|
|
113
|
+
if (preGlobbed) {
|
|
114
|
+
for (const f of preGlobbed) {
|
|
115
|
+
try {
|
|
116
|
+
const stat = fs.statSync(f);
|
|
117
|
+
hash.update(`${f}:${stat.mtimeMs}:${stat.size}`);
|
|
122
118
|
}
|
|
123
|
-
|
|
124
|
-
files.push(path.join(dir, f));
|
|
119
|
+
catch { /* skip */ }
|
|
125
120
|
}
|
|
126
|
-
catch { /* skip unreadable dirs */ }
|
|
127
121
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
122
|
+
else {
|
|
123
|
+
const projectDirs = getProjectDirs(cortexPath, profile);
|
|
124
|
+
const files = [];
|
|
125
|
+
for (const dir of projectDirs) {
|
|
126
|
+
try {
|
|
127
|
+
const matched = new Set();
|
|
128
|
+
for (const pattern of policy.includeGlobs) {
|
|
129
|
+
const dot = policy.includeHidden || pattern.startsWith(".") || pattern.includes("/.");
|
|
130
|
+
const mdFiles = globSync(pattern, { cwd: dir, nodir: true, dot, ignore: policy.excludeGlobs });
|
|
131
|
+
for (const f of mdFiles)
|
|
132
|
+
matched.add(f);
|
|
133
|
+
}
|
|
134
|
+
for (const f of matched)
|
|
135
|
+
files.push(path.join(dir, f));
|
|
136
|
+
}
|
|
137
|
+
catch { /* skip unreadable dirs */ }
|
|
138
|
+
}
|
|
139
|
+
files.sort();
|
|
140
|
+
for (const f of files) {
|
|
141
|
+
try {
|
|
142
|
+
const stat = fs.statSync(f);
|
|
143
|
+
hash.update(`${f}:${stat.mtimeMs}:${stat.size}`);
|
|
144
|
+
}
|
|
145
|
+
catch { /* skip */ }
|
|
134
146
|
}
|
|
135
|
-
catch { /* skip */ }
|
|
136
147
|
}
|
|
137
148
|
for (const mem of collectNativeMemoryFiles()) {
|
|
138
149
|
try {
|
|
@@ -227,10 +238,11 @@ function getEntrySourceDocKey(entry, cortexPath) {
|
|
|
227
238
|
}
|
|
228
239
|
return buildSourceDocKey(entry.project, entry.fullPath, cortexPath, entry.filename);
|
|
229
240
|
}
|
|
230
|
-
function
|
|
241
|
+
function globAllFiles(cortexPath, profile) {
|
|
231
242
|
const projectDirs = getProjectDirs(cortexPath, profile);
|
|
232
243
|
const indexPolicy = getIndexPolicy(cortexPath);
|
|
233
244
|
const entries = [];
|
|
245
|
+
const allAbsolutePaths = [];
|
|
234
246
|
for (const dir of projectDirs) {
|
|
235
247
|
const projectName = path.basename(dir);
|
|
236
248
|
const mdFilesSet = new Set();
|
|
@@ -255,12 +267,18 @@ function collectAllFiles(cortexPath, profile) {
|
|
|
255
267
|
const fullPath = path.join(dir, relFile);
|
|
256
268
|
const type = classifyFile(filename, relFile);
|
|
257
269
|
entries.push({ fullPath, project: projectName, filename, type, relFile });
|
|
270
|
+
allAbsolutePaths.push(fullPath);
|
|
258
271
|
}
|
|
259
272
|
}
|
|
260
273
|
for (const mem of collectNativeMemoryFiles()) {
|
|
261
274
|
entries.push({ fullPath: mem.fullPath, project: mem.project, filename: mem.file, type: "findings" });
|
|
275
|
+
allAbsolutePaths.push(mem.fullPath);
|
|
262
276
|
}
|
|
263
|
-
|
|
277
|
+
allAbsolutePaths.sort();
|
|
278
|
+
return { filePaths: allAbsolutePaths, entries };
|
|
279
|
+
}
|
|
280
|
+
function collectAllFiles(cortexPath, profile) {
|
|
281
|
+
return globAllFiles(cortexPath, profile).entries;
|
|
264
282
|
}
|
|
265
283
|
function insertFileIntoIndex(db, entry, cortexPath) {
|
|
266
284
|
try {
|
|
@@ -341,7 +359,8 @@ async function buildIndexImpl(cortexPath, profile) {
|
|
|
341
359
|
userSuffix = crypto.createHash("sha1").update(os.homedir()).digest("hex").slice(0, 12);
|
|
342
360
|
}
|
|
343
361
|
const cacheDir = path.join(os.tmpdir(), `cortex-fts-${userSuffix}`);
|
|
344
|
-
const
|
|
362
|
+
const globResult = globAllFiles(cortexPath, profile);
|
|
363
|
+
const hash = computeCortexHash(cortexPath, profile, globResult.filePaths);
|
|
345
364
|
const cacheFile = path.join(cacheDir, `${hash}.db`);
|
|
346
365
|
const wasmBinary = findWasmBinary();
|
|
347
366
|
const SQL = await initSqlJs(wasmBinary ? { wasmBinary } : {});
|
|
@@ -358,7 +377,7 @@ async function buildIndexImpl(cortexPath, profile) {
|
|
|
358
377
|
try {
|
|
359
378
|
db = new SQL.Database(cached);
|
|
360
379
|
// Compute current file hashes and determine what changed
|
|
361
|
-
const allFiles =
|
|
380
|
+
const allFiles = globResult.entries;
|
|
362
381
|
const currentHashes = {};
|
|
363
382
|
const changedFiles = [];
|
|
364
383
|
const newFiles = [];
|
|
@@ -487,7 +506,7 @@ async function buildIndexImpl(cortexPath, profile) {
|
|
|
487
506
|
db.run(`CREATE TABLE IF NOT EXISTS entity_links (source_id INTEGER REFERENCES entities(id), target_id INTEGER REFERENCES entities(id), rel_type TEXT NOT NULL, source_doc TEXT, PRIMARY KEY (source_id, target_id, rel_type))`);
|
|
488
507
|
// Q20: Cross-project entity index
|
|
489
508
|
ensureGlobalEntitiesTable(db);
|
|
490
|
-
const allFiles =
|
|
509
|
+
const allFiles = globResult.entries;
|
|
491
510
|
const newHashes = {};
|
|
492
511
|
let fileCount = 0;
|
|
493
512
|
// Try loading cached entity graph
|
package/mcp/dist/shared.js
CHANGED
|
@@ -209,6 +209,12 @@ export function collectNativeMemoryFiles() {
|
|
|
209
209
|
}
|
|
210
210
|
return results;
|
|
211
211
|
}
|
|
212
|
+
/** Canonical finding type tags */
|
|
213
|
+
export const FINDING_TYPES = ["decision", "pitfall", "pattern"];
|
|
214
|
+
/** All searchable finding tags (canonical + legacy aliases) */
|
|
215
|
+
export const FINDING_TAGS = ["decision", "pitfall", "pattern", "tradeoff", "architecture", "bug"];
|
|
216
|
+
/** Document types in the FTS index */
|
|
217
|
+
export const DOC_TYPES = ["claude", "findings", "reference", "skills", "summary", "backlog", "changelog", "canonical", "memory-queue", "skill", "other"];
|
|
212
218
|
export function appendAuditLog(cortexPath, event, details) {
|
|
213
219
|
// Migrate: check old location, use new .runtime/ path
|
|
214
220
|
const legacyPath = path.join(cortexPath, ".cortex-audit.log");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/cortex",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Long-term memory for AI agents
|
|
3
|
+
"version": "1.14.0",
|
|
4
|
+
"description": "Long-term memory for AI agents. Stored as markdown in a git repo you own.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cortex": "mcp/dist/index.js"
|
package/starter/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# My Cortex
|
|
2
2
|
|
|
3
|
-
Your personal project store for [cortex](https://github.com/alaarab/cortex)
|
|
3
|
+
Your personal project store for [cortex](https://github.com/alaarab/cortex), which gives Claude Code persistent context across sessions and machines.
|
|
4
4
|
|
|
5
5
|
## Structure
|
|
6
6
|
|
|
@@ -67,7 +67,7 @@ work-desktop: work
|
|
|
67
67
|
home-laptop: personal
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Each profile in `profiles/` lists which projects that machine should see. After cloning on a new machine, run `/cortex
|
|
70
|
+
Each profile in `profiles/` lists which projects that machine should see. After cloning on a new machine, run `/cortex-sync` to pull everything in.
|
|
71
71
|
|
|
72
72
|
## Troubleshooting
|
|
73
73
|
|