threadnote 1.1.6 → 1.2.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/.threadnoteignore +2 -0
- package/dist/mcp_server.cjs +119 -19
- package/dist/threadnote.cjs +119 -27
- package/package.json +1 -1
package/.threadnoteignore
CHANGED
package/dist/mcp_server.cjs
CHANGED
|
@@ -36193,6 +36193,7 @@ function grepUrisFromJson(output) {
|
|
|
36193
36193
|
}
|
|
36194
36194
|
}
|
|
36195
36195
|
var RECALL_CATEGORY_ORDER = ["memories", "resources", "skills"];
|
|
36196
|
+
var RECALL_PROMOTED_EXACT_SCORE = 0;
|
|
36196
36197
|
function recallSnippet(value) {
|
|
36197
36198
|
if (typeof value !== "string") {
|
|
36198
36199
|
return "";
|
|
@@ -36244,11 +36245,14 @@ function parseRecallHits(output, options = {}) {
|
|
|
36244
36245
|
return [];
|
|
36245
36246
|
}
|
|
36246
36247
|
}
|
|
36248
|
+
function stripAnchor(uri) {
|
|
36249
|
+
return uri.replace(/#.*$/, "");
|
|
36250
|
+
}
|
|
36247
36251
|
function mergeRecallHits(passes) {
|
|
36248
36252
|
const byDocument = /* @__PURE__ */ new Map();
|
|
36249
36253
|
for (const pass of passes) {
|
|
36250
36254
|
for (const hit of pass) {
|
|
36251
|
-
const documentUri = hit.uri
|
|
36255
|
+
const documentUri = stripAnchor(hit.uri);
|
|
36252
36256
|
const existing = byDocument.get(documentUri);
|
|
36253
36257
|
if (!existing || hit.score > existing.score) {
|
|
36254
36258
|
byDocument.set(documentUri, { ...hit, uri: documentUri });
|
|
@@ -36256,23 +36260,120 @@ function mergeRecallHits(passes) {
|
|
|
36256
36260
|
}
|
|
36257
36261
|
}
|
|
36258
36262
|
return [...byDocument.values()].sort(
|
|
36259
|
-
(left, right) =>
|
|
36263
|
+
(left, right) => recallCategoryRank(left.category) - recallCategoryRank(right.category) || right.score - left.score
|
|
36264
|
+
);
|
|
36265
|
+
}
|
|
36266
|
+
function recallCategoryRank(category) {
|
|
36267
|
+
const index = RECALL_CATEGORY_ORDER.indexOf(category);
|
|
36268
|
+
return index === -1 ? RECALL_CATEGORY_ORDER.length : index;
|
|
36269
|
+
}
|
|
36270
|
+
function dedupeByContent(hits) {
|
|
36271
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36272
|
+
const kept = [];
|
|
36273
|
+
for (const hit of hits) {
|
|
36274
|
+
if (hit.category !== "memories" && hit.snippet.length > 0) {
|
|
36275
|
+
const key = `${hit.category}
|
|
36276
|
+
${hit.snippet}`;
|
|
36277
|
+
if (seen.has(key)) {
|
|
36278
|
+
continue;
|
|
36279
|
+
}
|
|
36280
|
+
seen.add(key);
|
|
36281
|
+
}
|
|
36282
|
+
kept.push(hit);
|
|
36283
|
+
}
|
|
36284
|
+
return kept;
|
|
36285
|
+
}
|
|
36286
|
+
function categoryForUri(uri) {
|
|
36287
|
+
if (uri.includes("/memories/")) {
|
|
36288
|
+
return "memories";
|
|
36289
|
+
}
|
|
36290
|
+
if (uri.startsWith("viking://resources/agent-skills/")) {
|
|
36291
|
+
return "skills";
|
|
36292
|
+
}
|
|
36293
|
+
return "resources";
|
|
36294
|
+
}
|
|
36295
|
+
function contextTypeForCategory(category) {
|
|
36296
|
+
if (category === "memories") {
|
|
36297
|
+
return "memory";
|
|
36298
|
+
}
|
|
36299
|
+
return category === "skills" ? "skill" : "resource";
|
|
36300
|
+
}
|
|
36301
|
+
function applyExactMatchBoost(hits, exactMatches) {
|
|
36302
|
+
if (exactMatches.length === 0) {
|
|
36303
|
+
return hits;
|
|
36304
|
+
}
|
|
36305
|
+
const termsByUri = new Map(exactMatches.map((match) => [stripAnchor(match.uri), match.terms]));
|
|
36306
|
+
const annotated = hits.map((hit) => {
|
|
36307
|
+
const terms = termsByUri.get(stripAnchor(hit.uri));
|
|
36308
|
+
return terms ? { ...hit, exactTerms: terms } : hit;
|
|
36309
|
+
});
|
|
36310
|
+
const present = new Set(annotated.map((hit) => stripAnchor(hit.uri)));
|
|
36311
|
+
const promoted = [...termsByUri.keys()].filter((uri) => !present.has(uri)).map((uri) => {
|
|
36312
|
+
const category = categoryForUri(uri);
|
|
36313
|
+
return {
|
|
36314
|
+
category,
|
|
36315
|
+
contextType: contextTypeForCategory(category),
|
|
36316
|
+
exactTerms: termsByUri.get(uri) ?? [],
|
|
36317
|
+
score: RECALL_PROMOTED_EXACT_SCORE,
|
|
36318
|
+
snippet: "",
|
|
36319
|
+
uri
|
|
36320
|
+
};
|
|
36321
|
+
});
|
|
36322
|
+
return [...annotated, ...promoted].sort(
|
|
36323
|
+
(left, right) => recallCategoryRank(left.category) - recallCategoryRank(right.category) || (right.exactTerms?.length ?? 0) - (left.exactTerms?.length ?? 0) || right.score - left.score
|
|
36260
36324
|
);
|
|
36261
36325
|
}
|
|
36262
|
-
function
|
|
36263
|
-
if (
|
|
36326
|
+
function renderRecallHits(shown, overflow) {
|
|
36327
|
+
if (shown.length === 0) {
|
|
36264
36328
|
return void 0;
|
|
36265
36329
|
}
|
|
36266
|
-
const shown = hits.slice(0, maxHits);
|
|
36267
36330
|
const lines = shown.flatMap((hit, index) => {
|
|
36268
|
-
const
|
|
36331
|
+
const scorePart = hit.score > 0 ? `score ${hit.score.toFixed(2)}` : void 0;
|
|
36332
|
+
const exactPart = hit.exactTerms?.length ? `exact: ${hit.exactTerms.join(", ")}` : void 0;
|
|
36333
|
+
const head = `${index + 1}. ${[hit.contextType, scorePart, exactPart].filter(Boolean).join(" \xB7 ")} \xB7 ${hit.uri}`;
|
|
36269
36334
|
return hit.snippet ? [head, ` ${hit.snippet}`] : [head];
|
|
36270
36335
|
});
|
|
36271
|
-
if (
|
|
36272
|
-
lines.push(`(+${
|
|
36336
|
+
if (overflow > 0) {
|
|
36337
|
+
lines.push(`(+${overflow} more \u2014 refine the query or read a URI above)`);
|
|
36273
36338
|
}
|
|
36274
36339
|
return lines.join("\n");
|
|
36275
36340
|
}
|
|
36341
|
+
var RECALL_CATEGORY_RESERVE = 2;
|
|
36342
|
+
function selectShownHits(ranked, limit, reserve) {
|
|
36343
|
+
if (ranked.length <= limit) {
|
|
36344
|
+
return ranked;
|
|
36345
|
+
}
|
|
36346
|
+
const selected = /* @__PURE__ */ new Set();
|
|
36347
|
+
for (const category of RECALL_CATEGORY_ORDER) {
|
|
36348
|
+
let taken = 0;
|
|
36349
|
+
for (const hit of ranked) {
|
|
36350
|
+
if (selected.size >= limit || taken >= reserve) {
|
|
36351
|
+
break;
|
|
36352
|
+
}
|
|
36353
|
+
if (hit.category === category && !selected.has(hit.uri)) {
|
|
36354
|
+
selected.add(hit.uri);
|
|
36355
|
+
taken += 1;
|
|
36356
|
+
}
|
|
36357
|
+
}
|
|
36358
|
+
}
|
|
36359
|
+
for (const hit of ranked) {
|
|
36360
|
+
if (selected.size >= limit) {
|
|
36361
|
+
break;
|
|
36362
|
+
}
|
|
36363
|
+
selected.add(hit.uri);
|
|
36364
|
+
}
|
|
36365
|
+
return ranked.filter((hit) => selected.has(hit.uri));
|
|
36366
|
+
}
|
|
36367
|
+
function buildRecallSections(passes, exactMatches, limit) {
|
|
36368
|
+
const ranked = dedupeByContent(applyExactMatchBoost(mergeRecallHits(passes), exactMatches));
|
|
36369
|
+
const shown = selectShownHits(ranked, limit, RECALL_CATEGORY_RESERVE);
|
|
36370
|
+
const shownUris = new Set(shown.map((hit) => stripAnchor(hit.uri)));
|
|
36371
|
+
return {
|
|
36372
|
+
exactTail: formatExactMatchPointers(exactMatches.filter((match) => !shownUris.has(stripAnchor(match.uri)))),
|
|
36373
|
+
ranked,
|
|
36374
|
+
semanticSection: renderRecallHits(shown, ranked.length - shown.length)
|
|
36375
|
+
};
|
|
36376
|
+
}
|
|
36276
36377
|
function exactMemoryScopeUris(params) {
|
|
36277
36378
|
const { agentMemoriesUri, includeArchived, intents, projectName, projectResourceUri, userBase } = params;
|
|
36278
36379
|
const durable = projectName ? `${userBase}/durable/projects/${projectName}` : `${userBase}/durable/projects`;
|
|
@@ -38457,14 +38558,14 @@ function registerTools(server, config2) {
|
|
|
38457
38558
|
"grep",
|
|
38458
38559
|
{
|
|
38459
38560
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
38460
|
-
description: "Run exact text search in OpenViking.",
|
|
38561
|
+
description: "Run exact text search in OpenViking. Defaults to your memories subtree when uri is omitted (OpenViking grep requires a scope).",
|
|
38461
38562
|
inputSchema: {
|
|
38462
38563
|
caseInsensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
|
|
38463
38564
|
case_insensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
|
|
38464
38565
|
nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
|
|
38465
38566
|
node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
|
|
38466
38567
|
pattern: external_exports.string().optional().describe("Required text or regex pattern"),
|
|
38467
|
-
uri: external_exports.string().optional().describe("Optional viking:// subtree")
|
|
38568
|
+
uri: external_exports.string().optional().describe("Optional viking:// subtree (defaults to your memories root)")
|
|
38468
38569
|
}
|
|
38469
38570
|
},
|
|
38470
38571
|
async ({ caseInsensitive, case_insensitive, nodeLimit, node_limit, pattern, uri }) => {
|
|
@@ -38480,7 +38581,7 @@ function registerTools(server, config2) {
|
|
|
38480
38581
|
case_insensitive: caseInsensitive ?? case_insensitive,
|
|
38481
38582
|
node_limit: nodeLimit ?? node_limit,
|
|
38482
38583
|
pattern: checkedPattern.value,
|
|
38483
|
-
uri: checkedUri.value
|
|
38584
|
+
uri: checkedUri.value ?? `viking://user/${uriSegment2(config2.user)}/memories`
|
|
38484
38585
|
});
|
|
38485
38586
|
}
|
|
38486
38587
|
);
|
|
@@ -39045,7 +39146,8 @@ async function runRecallTool(config2, params) {
|
|
|
39045
39146
|
passes.push(seeded.hits);
|
|
39046
39147
|
}
|
|
39047
39148
|
const sections = [];
|
|
39048
|
-
const
|
|
39149
|
+
const exactMatches = await collectExactMemoryMatches(config2, query, params.includeArchived, project);
|
|
39150
|
+
const { semanticSection, exactTail } = buildRecallSections(passes, exactMatches, params.nodeLimit ?? 12);
|
|
39049
39151
|
if (semanticSection) {
|
|
39050
39152
|
sections.push(semanticSection);
|
|
39051
39153
|
} else if (!base.ok) {
|
|
@@ -39054,9 +39156,8 @@ async function runRecallTool(config2, params) {
|
|
|
39054
39156
|
if (indexRepairMessages.length > 0) {
|
|
39055
39157
|
sections.push(indexRepairMessages.join("\n"));
|
|
39056
39158
|
}
|
|
39057
|
-
|
|
39058
|
-
|
|
39059
|
-
sections.push(exactMatches);
|
|
39159
|
+
if (exactTail) {
|
|
39160
|
+
sections.push(exactTail);
|
|
39060
39161
|
}
|
|
39061
39162
|
const hygieneHints = await recallHygieneHintsSection(config2, sections.join("\n\n"));
|
|
39062
39163
|
if (hygieneHints) {
|
|
@@ -39103,14 +39204,14 @@ async function recallHygieneHintsSection(config2, recallText) {
|
|
|
39103
39204
|
const nudges = recallHygieneNudges(recallText, { records, user: config2.user });
|
|
39104
39205
|
return nudges.length > 0 ? ["Memory hygiene hints:", ...nudges.map((nudge) => `- ${nudge}`)].join("\n") : void 0;
|
|
39105
39206
|
}
|
|
39106
|
-
async function
|
|
39207
|
+
async function collectExactMemoryMatches(config2, query, includeArchived, project) {
|
|
39107
39208
|
const terms = exactRecallTerms(query);
|
|
39108
39209
|
if (terms.length === 0) {
|
|
39109
|
-
return
|
|
39210
|
+
return [];
|
|
39110
39211
|
}
|
|
39111
39212
|
const ov = await requiredOpenVikingCli2();
|
|
39112
39213
|
const scopes = exactMemoryScopes(config2, includeArchived, query, project);
|
|
39113
|
-
|
|
39214
|
+
return collectExactMatches(terms, scopes, async (term, scope) => {
|
|
39114
39215
|
const result = await runCommand(
|
|
39115
39216
|
ov,
|
|
39116
39217
|
withIdentity2(config2, ["grep", term, "--uri", scope, "--node-limit", "5", "--output", "json"]),
|
|
@@ -39118,7 +39219,6 @@ async function exactMemoryMatchesText(config2, query, includeArchived, project)
|
|
|
39118
39219
|
);
|
|
39119
39220
|
return result.exitCode === 0 ? result.stdout : void 0;
|
|
39120
39221
|
});
|
|
39121
|
-
return formatExactMatchPointers(matches);
|
|
39122
39222
|
}
|
|
39123
39223
|
function registerReadTool(server, config2, name, description) {
|
|
39124
39224
|
server.registerTool(
|
package/dist/threadnote.cjs
CHANGED
|
@@ -4349,6 +4349,7 @@ function grepUrisFromJson(output2) {
|
|
|
4349
4349
|
}
|
|
4350
4350
|
}
|
|
4351
4351
|
var RECALL_CATEGORY_ORDER = ["memories", "resources", "skills"];
|
|
4352
|
+
var RECALL_PROMOTED_EXACT_SCORE = 0;
|
|
4352
4353
|
function recallSnippet(value) {
|
|
4353
4354
|
if (typeof value !== "string") {
|
|
4354
4355
|
return "";
|
|
@@ -4400,11 +4401,14 @@ function parseRecallHits(output2, options = {}) {
|
|
|
4400
4401
|
return [];
|
|
4401
4402
|
}
|
|
4402
4403
|
}
|
|
4404
|
+
function stripAnchor(uri) {
|
|
4405
|
+
return uri.replace(/#.*$/, "");
|
|
4406
|
+
}
|
|
4403
4407
|
function mergeRecallHits(passes) {
|
|
4404
4408
|
const byDocument = /* @__PURE__ */ new Map();
|
|
4405
4409
|
for (const pass of passes) {
|
|
4406
4410
|
for (const hit of pass) {
|
|
4407
|
-
const documentUri = hit.uri
|
|
4411
|
+
const documentUri = stripAnchor(hit.uri);
|
|
4408
4412
|
const existing = byDocument.get(documentUri);
|
|
4409
4413
|
if (!existing || hit.score > existing.score) {
|
|
4410
4414
|
byDocument.set(documentUri, { ...hit, uri: documentUri });
|
|
@@ -4412,23 +4416,120 @@ function mergeRecallHits(passes) {
|
|
|
4412
4416
|
}
|
|
4413
4417
|
}
|
|
4414
4418
|
return [...byDocument.values()].sort(
|
|
4415
|
-
(left, right) =>
|
|
4419
|
+
(left, right) => recallCategoryRank(left.category) - recallCategoryRank(right.category) || right.score - left.score
|
|
4416
4420
|
);
|
|
4417
4421
|
}
|
|
4418
|
-
function
|
|
4419
|
-
|
|
4422
|
+
function recallCategoryRank(category) {
|
|
4423
|
+
const index = RECALL_CATEGORY_ORDER.indexOf(category);
|
|
4424
|
+
return index === -1 ? RECALL_CATEGORY_ORDER.length : index;
|
|
4425
|
+
}
|
|
4426
|
+
function dedupeByContent(hits) {
|
|
4427
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4428
|
+
const kept = [];
|
|
4429
|
+
for (const hit of hits) {
|
|
4430
|
+
if (hit.category !== "memories" && hit.snippet.length > 0) {
|
|
4431
|
+
const key = `${hit.category}
|
|
4432
|
+
${hit.snippet}`;
|
|
4433
|
+
if (seen.has(key)) {
|
|
4434
|
+
continue;
|
|
4435
|
+
}
|
|
4436
|
+
seen.add(key);
|
|
4437
|
+
}
|
|
4438
|
+
kept.push(hit);
|
|
4439
|
+
}
|
|
4440
|
+
return kept;
|
|
4441
|
+
}
|
|
4442
|
+
function categoryForUri(uri) {
|
|
4443
|
+
if (uri.includes("/memories/")) {
|
|
4444
|
+
return "memories";
|
|
4445
|
+
}
|
|
4446
|
+
if (uri.startsWith("viking://resources/agent-skills/")) {
|
|
4447
|
+
return "skills";
|
|
4448
|
+
}
|
|
4449
|
+
return "resources";
|
|
4450
|
+
}
|
|
4451
|
+
function contextTypeForCategory(category) {
|
|
4452
|
+
if (category === "memories") {
|
|
4453
|
+
return "memory";
|
|
4454
|
+
}
|
|
4455
|
+
return category === "skills" ? "skill" : "resource";
|
|
4456
|
+
}
|
|
4457
|
+
function applyExactMatchBoost(hits, exactMatches) {
|
|
4458
|
+
if (exactMatches.length === 0) {
|
|
4459
|
+
return hits;
|
|
4460
|
+
}
|
|
4461
|
+
const termsByUri = new Map(exactMatches.map((match) => [stripAnchor(match.uri), match.terms]));
|
|
4462
|
+
const annotated = hits.map((hit) => {
|
|
4463
|
+
const terms = termsByUri.get(stripAnchor(hit.uri));
|
|
4464
|
+
return terms ? { ...hit, exactTerms: terms } : hit;
|
|
4465
|
+
});
|
|
4466
|
+
const present = new Set(annotated.map((hit) => stripAnchor(hit.uri)));
|
|
4467
|
+
const promoted = [...termsByUri.keys()].filter((uri) => !present.has(uri)).map((uri) => {
|
|
4468
|
+
const category = categoryForUri(uri);
|
|
4469
|
+
return {
|
|
4470
|
+
category,
|
|
4471
|
+
contextType: contextTypeForCategory(category),
|
|
4472
|
+
exactTerms: termsByUri.get(uri) ?? [],
|
|
4473
|
+
score: RECALL_PROMOTED_EXACT_SCORE,
|
|
4474
|
+
snippet: "",
|
|
4475
|
+
uri
|
|
4476
|
+
};
|
|
4477
|
+
});
|
|
4478
|
+
return [...annotated, ...promoted].sort(
|
|
4479
|
+
(left, right) => recallCategoryRank(left.category) - recallCategoryRank(right.category) || (right.exactTerms?.length ?? 0) - (left.exactTerms?.length ?? 0) || right.score - left.score
|
|
4480
|
+
);
|
|
4481
|
+
}
|
|
4482
|
+
function renderRecallHits(shown, overflow) {
|
|
4483
|
+
if (shown.length === 0) {
|
|
4420
4484
|
return void 0;
|
|
4421
4485
|
}
|
|
4422
|
-
const shown = hits.slice(0, maxHits);
|
|
4423
4486
|
const lines = shown.flatMap((hit, index) => {
|
|
4424
|
-
const
|
|
4487
|
+
const scorePart = hit.score > 0 ? `score ${hit.score.toFixed(2)}` : void 0;
|
|
4488
|
+
const exactPart = hit.exactTerms?.length ? `exact: ${hit.exactTerms.join(", ")}` : void 0;
|
|
4489
|
+
const head = `${index + 1}. ${[hit.contextType, scorePart, exactPart].filter(Boolean).join(" \xB7 ")} \xB7 ${hit.uri}`;
|
|
4425
4490
|
return hit.snippet ? [head, ` ${hit.snippet}`] : [head];
|
|
4426
4491
|
});
|
|
4427
|
-
if (
|
|
4428
|
-
lines.push(`(+${
|
|
4492
|
+
if (overflow > 0) {
|
|
4493
|
+
lines.push(`(+${overflow} more \u2014 refine the query or read a URI above)`);
|
|
4429
4494
|
}
|
|
4430
4495
|
return lines.join("\n");
|
|
4431
4496
|
}
|
|
4497
|
+
var RECALL_CATEGORY_RESERVE = 2;
|
|
4498
|
+
function selectShownHits(ranked, limit, reserve) {
|
|
4499
|
+
if (ranked.length <= limit) {
|
|
4500
|
+
return ranked;
|
|
4501
|
+
}
|
|
4502
|
+
const selected = /* @__PURE__ */ new Set();
|
|
4503
|
+
for (const category of RECALL_CATEGORY_ORDER) {
|
|
4504
|
+
let taken = 0;
|
|
4505
|
+
for (const hit of ranked) {
|
|
4506
|
+
if (selected.size >= limit || taken >= reserve) {
|
|
4507
|
+
break;
|
|
4508
|
+
}
|
|
4509
|
+
if (hit.category === category && !selected.has(hit.uri)) {
|
|
4510
|
+
selected.add(hit.uri);
|
|
4511
|
+
taken += 1;
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
for (const hit of ranked) {
|
|
4516
|
+
if (selected.size >= limit) {
|
|
4517
|
+
break;
|
|
4518
|
+
}
|
|
4519
|
+
selected.add(hit.uri);
|
|
4520
|
+
}
|
|
4521
|
+
return ranked.filter((hit) => selected.has(hit.uri));
|
|
4522
|
+
}
|
|
4523
|
+
function buildRecallSections(passes, exactMatches, limit) {
|
|
4524
|
+
const ranked = dedupeByContent(applyExactMatchBoost(mergeRecallHits(passes), exactMatches));
|
|
4525
|
+
const shown = selectShownHits(ranked, limit, RECALL_CATEGORY_RESERVE);
|
|
4526
|
+
const shownUris = new Set(shown.map((hit) => stripAnchor(hit.uri)));
|
|
4527
|
+
return {
|
|
4528
|
+
exactTail: formatExactMatchPointers(exactMatches.filter((match) => !shownUris.has(stripAnchor(match.uri)))),
|
|
4529
|
+
ranked,
|
|
4530
|
+
semanticSection: renderRecallHits(shown, ranked.length - shown.length)
|
|
4531
|
+
};
|
|
4532
|
+
}
|
|
4432
4533
|
function exactMemoryScopeUris(params) {
|
|
4433
4534
|
const { agentMemoriesUri, includeArchived, intents, projectName, projectResourceUri, userBase } = params;
|
|
4434
4535
|
const durable = projectName ? `${userBase}/durable/projects/${projectName}` : `${userBase}/durable/projects`;
|
|
@@ -10478,19 +10579,17 @@ async function runRecall(config, options) {
|
|
|
10478
10579
|
passes.push(await recallSearchHits(config, ov, searchArgs(seededUri), { dryRun, includeArchived }));
|
|
10479
10580
|
}
|
|
10480
10581
|
const recallOutputs = [];
|
|
10481
|
-
const
|
|
10582
|
+
const exactMatches = await collectExactMemoryMatches(config, ov, query, { dryRun, includeArchived, project });
|
|
10583
|
+
const { semanticSection, exactTail } = buildRecallSections(passes, exactMatches, nodeLimit ?? 12);
|
|
10482
10584
|
if (semanticSection) {
|
|
10483
10585
|
console.log(`
|
|
10484
10586
|
${semanticSection}`);
|
|
10485
10587
|
recallOutputs.push(semanticSection);
|
|
10486
10588
|
}
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
});
|
|
10492
|
-
if (exactOutput) {
|
|
10493
|
-
recallOutputs.push(exactOutput);
|
|
10589
|
+
if (exactTail) {
|
|
10590
|
+
console.log(`
|
|
10591
|
+
${exactTail}`);
|
|
10592
|
+
recallOutputs.push(exactTail);
|
|
10494
10593
|
}
|
|
10495
10594
|
await printRecallHygieneNudges(config, recallOutputs.join("\n"));
|
|
10496
10595
|
}
|
|
@@ -10854,10 +10953,10 @@ function hasAgentSkillCatalogIntent(query) {
|
|
|
10854
10953
|
}
|
|
10855
10954
|
return /\b(find|list|show|search|recall|use|choose|select)\b.{0,48}\bskills?\b/.test(normalized) || /\bskills?\b.{0,48}\b(for|to|that|which|about)\b/.test(normalized);
|
|
10856
10955
|
}
|
|
10857
|
-
async function
|
|
10956
|
+
async function collectExactMemoryMatches(config, ov, query, options) {
|
|
10858
10957
|
const terms = exactRecallTerms(query);
|
|
10859
10958
|
if (terms.length === 0) {
|
|
10860
|
-
return
|
|
10959
|
+
return [];
|
|
10861
10960
|
}
|
|
10862
10961
|
const scopes = exactMemoryScopes(config, options.includeArchived, query, options.project);
|
|
10863
10962
|
const grepArgs = (term, scope) => withIdentity(config, ["grep", term, "--uri", scope, "--node-limit", "5", "--output", "json"]);
|
|
@@ -10865,19 +10964,12 @@ async function printExactMemoryMatches(config, ov, query, options) {
|
|
|
10865
10964
|
const planned = terms.flatMap((term) => scopes.map((scope) => formatShellCommand(ov, grepArgs(term, scope))));
|
|
10866
10965
|
console.log("\nExact memory/resource matches:");
|
|
10867
10966
|
console.log(planned.join("\n"));
|
|
10868
|
-
return
|
|
10967
|
+
return [];
|
|
10869
10968
|
}
|
|
10870
|
-
|
|
10969
|
+
return collectExactMatches(terms, scopes, async (term, scope) => {
|
|
10871
10970
|
const result = await runCommand(ov, grepArgs(term, scope), { allowFailure: true });
|
|
10872
10971
|
return result.exitCode === 0 ? result.stdout : void 0;
|
|
10873
10972
|
});
|
|
10874
|
-
const text = formatExactMatchPointers(matches);
|
|
10875
|
-
if (!text) {
|
|
10876
|
-
return void 0;
|
|
10877
|
-
}
|
|
10878
|
-
console.log(`
|
|
10879
|
-
${text}`);
|
|
10880
|
-
return text;
|
|
10881
10973
|
}
|
|
10882
10974
|
async function storeMemory(config, options) {
|
|
10883
10975
|
if (options.replaceUri) {
|