@danielblomma/cortex-mcp 2.2.0 → 2.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/package.json +1 -1
- package/scaffold/scripts/ingest.mjs +67 -21
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielblomma/cortex-mcp",
|
|
3
3
|
"mcpName": "io.github.DanielBlomma/cortex",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.1",
|
|
5
5
|
"description": "Local, repo-scoped context platform for coding assistants. Semantic search, graph relationships, and architectural rule context.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Daniel Blomma",
|
|
@@ -2056,6 +2056,27 @@ function fileTokenSet(fileRecord) {
|
|
|
2056
2056
|
return new Set(tokenizeKeywords(tokenSource));
|
|
2057
2057
|
}
|
|
2058
2058
|
|
|
2059
|
+
function collectRuleKeywordMatch(ruleKeywords, tokens, minimumMatches) {
|
|
2060
|
+
const required = Math.min(minimumMatches, Math.max(1, ruleKeywords.length));
|
|
2061
|
+
let count = 0;
|
|
2062
|
+
const sample = [];
|
|
2063
|
+
|
|
2064
|
+
for (const keyword of ruleKeywords) {
|
|
2065
|
+
if (!tokens.has(keyword)) {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
count += 1;
|
|
2069
|
+
if (sample.length < 5) {
|
|
2070
|
+
sample.push(keyword);
|
|
2071
|
+
}
|
|
2072
|
+
if (count >= required && sample.length >= 5) {
|
|
2073
|
+
break;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
return { matched: count >= required, sample };
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2059
2080
|
function chunkIdFor(filePath, chunk) {
|
|
2060
2081
|
const startLine = Number.isFinite(chunk.startLine) ? chunk.startLine : 0;
|
|
2061
2082
|
const endLine = Number.isFinite(chunk.endLine) ? chunk.endLine : startLine;
|
|
@@ -3331,59 +3352,84 @@ async function main() {
|
|
|
3331
3352
|
|
|
3332
3353
|
const constrainsRelations = [];
|
|
3333
3354
|
const implementsRelations = [];
|
|
3334
|
-
const constrainsSeen = new Set();
|
|
3335
|
-
const implementsSeen = new Set();
|
|
3336
3355
|
memoryTrace.checkpoint("tokens:rule_matching_start", {
|
|
3337
3356
|
files: fileRecords.length,
|
|
3338
3357
|
rules: ruleRecords.length
|
|
3339
3358
|
});
|
|
3340
|
-
const tokenByFileId = new Map(fileRecords.map((fileRecord) => [fileRecord.id, fileTokenSet(fileRecord)]));
|
|
3341
3359
|
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3360
|
+
const ruleMatchers = ruleRecords.map((ruleRecord) => ({
|
|
3361
|
+
ruleRecord,
|
|
3362
|
+
needle: ruleRecord.id.toLowerCase(),
|
|
3363
|
+
keywords: normalizeRuleTokens(ruleRecord)
|
|
3364
|
+
}));
|
|
3365
|
+
const constrainsByKey = new Map();
|
|
3366
|
+
const implementsByKey = new Map();
|
|
3367
|
+
let fileTokenSetsProcessed = 0;
|
|
3345
3368
|
|
|
3346
|
-
|
|
3347
|
-
|
|
3369
|
+
for (const fileRecord of fileRecords) {
|
|
3370
|
+
const lower = fileRecord.content.toLowerCase();
|
|
3371
|
+
const tokens = fileTokenSet(fileRecord);
|
|
3372
|
+
fileTokenSetsProcessed += 1;
|
|
3373
|
+
|
|
3374
|
+
for (const { ruleRecord, needle, keywords } of ruleMatchers) {
|
|
3348
3375
|
const explicitMention = lower.includes(needle);
|
|
3349
|
-
const tokens = tokenByFileId.get(fileRecord.id) ?? new Set();
|
|
3350
|
-
const matchedKeywords = ruleKeywords.filter((keyword) => tokens.has(keyword));
|
|
3351
3376
|
const minimumMatches = fileRecord.kind === "CODE" ? 1 : 2;
|
|
3352
|
-
const
|
|
3377
|
+
const keywordResult = explicitMention
|
|
3378
|
+
? { matched: false, sample: [] }
|
|
3379
|
+
: collectRuleKeywordMatch(keywords, tokens, minimumMatches);
|
|
3353
3380
|
|
|
3354
|
-
if (!explicitMention && !
|
|
3381
|
+
if (!explicitMention && !keywordResult.matched) {
|
|
3355
3382
|
continue;
|
|
3356
3383
|
}
|
|
3357
3384
|
|
|
3358
3385
|
const constrainsKey = `${ruleRecord.id}|${fileRecord.id}`;
|
|
3359
|
-
if (!
|
|
3360
|
-
|
|
3361
|
-
constrainsRelations.push({
|
|
3386
|
+
if (!constrainsByKey.has(constrainsKey)) {
|
|
3387
|
+
constrainsByKey.set(constrainsKey, {
|
|
3362
3388
|
from: ruleRecord.id,
|
|
3363
3389
|
to: fileRecord.id,
|
|
3364
3390
|
note: explicitMention
|
|
3365
3391
|
? `Mentions ${ruleRecord.id}`
|
|
3366
|
-
: `Keyword match ${
|
|
3392
|
+
: `Keyword match ${keywordResult.sample.join(", ")}`
|
|
3367
3393
|
});
|
|
3368
3394
|
}
|
|
3369
3395
|
|
|
3370
3396
|
if (fileRecord.kind === "CODE") {
|
|
3371
3397
|
const implementsKey = `${fileRecord.id}|${ruleRecord.id}`;
|
|
3372
|
-
if (!
|
|
3373
|
-
|
|
3374
|
-
implementsRelations.push({
|
|
3398
|
+
if (!implementsByKey.has(implementsKey)) {
|
|
3399
|
+
implementsByKey.set(implementsKey, {
|
|
3375
3400
|
from: fileRecord.id,
|
|
3376
3401
|
to: ruleRecord.id,
|
|
3377
3402
|
note: explicitMention
|
|
3378
3403
|
? `Code references ${ruleRecord.id}`
|
|
3379
|
-
: `Code keywords ${
|
|
3404
|
+
: `Code keywords ${keywordResult.sample.join(", ")}`
|
|
3380
3405
|
});
|
|
3381
3406
|
}
|
|
3382
3407
|
}
|
|
3383
3408
|
}
|
|
3384
3409
|
}
|
|
3410
|
+
|
|
3411
|
+
for (const { ruleRecord } of ruleMatchers) {
|
|
3412
|
+
for (const fileRecord of fileRecords) {
|
|
3413
|
+
const constrainsKey = `${ruleRecord.id}|${fileRecord.id}`;
|
|
3414
|
+
const constrainsRelation = constrainsByKey.get(constrainsKey);
|
|
3415
|
+
if (constrainsRelation) {
|
|
3416
|
+
constrainsRelations.push(constrainsRelation);
|
|
3417
|
+
constrainsByKey.delete(constrainsKey);
|
|
3418
|
+
}
|
|
3419
|
+
if (fileRecord.kind === "CODE") {
|
|
3420
|
+
const implementsKey = `${fileRecord.id}|${ruleRecord.id}`;
|
|
3421
|
+
const implementsRelation = implementsByKey.get(implementsKey);
|
|
3422
|
+
if (implementsRelation) {
|
|
3423
|
+
implementsRelations.push(implementsRelation);
|
|
3424
|
+
implementsByKey.delete(implementsKey);
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3385
3430
|
memoryTrace.checkpoint("tokens:rule_matching_complete", {
|
|
3386
|
-
file_token_sets:
|
|
3431
|
+
file_token_sets: fileTokenSetsProcessed,
|
|
3432
|
+
file_token_sets_retained: 0,
|
|
3387
3433
|
rules: ruleRecords.length,
|
|
3388
3434
|
relations_constrains: constrainsRelations.length,
|
|
3389
3435
|
relations_implements: implementsRelations.length,
|