nodebench-mcp 2.22.0 → 2.25.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.
Files changed (38) hide show
  1. package/README.md +366 -280
  2. package/dist/__tests__/multiHopDogfood.test.d.ts +12 -0
  3. package/dist/__tests__/multiHopDogfood.test.js +303 -0
  4. package/dist/__tests__/multiHopDogfood.test.js.map +1 -0
  5. package/dist/__tests__/presetRealWorldBench.test.js +2 -0
  6. package/dist/__tests__/presetRealWorldBench.test.js.map +1 -1
  7. package/dist/__tests__/tools.test.js +158 -6
  8. package/dist/__tests__/tools.test.js.map +1 -1
  9. package/dist/__tests__/toolsetGatingEval.test.js +2 -0
  10. package/dist/__tests__/toolsetGatingEval.test.js.map +1 -1
  11. package/dist/dashboard/html.d.ts +18 -0
  12. package/dist/dashboard/html.js +1251 -0
  13. package/dist/dashboard/html.js.map +1 -0
  14. package/dist/dashboard/server.d.ts +17 -0
  15. package/dist/dashboard/server.js +278 -0
  16. package/dist/dashboard/server.js.map +1 -0
  17. package/dist/db.js +38 -0
  18. package/dist/db.js.map +1 -1
  19. package/dist/index.js +19 -9
  20. package/dist/index.js.map +1 -1
  21. package/dist/tools/prReportTools.d.ts +11 -0
  22. package/dist/tools/prReportTools.js +911 -0
  23. package/dist/tools/prReportTools.js.map +1 -0
  24. package/dist/tools/progressiveDiscoveryTools.js +111 -24
  25. package/dist/tools/progressiveDiscoveryTools.js.map +1 -1
  26. package/dist/tools/skillUpdateTools.d.ts +24 -0
  27. package/dist/tools/skillUpdateTools.js +469 -0
  28. package/dist/tools/skillUpdateTools.js.map +1 -0
  29. package/dist/tools/toolRegistry.d.ts +15 -1
  30. package/dist/tools/toolRegistry.js +315 -11
  31. package/dist/tools/toolRegistry.js.map +1 -1
  32. package/dist/tools/uiUxDiveAdvancedTools.js +61 -0
  33. package/dist/tools/uiUxDiveAdvancedTools.js.map +1 -1
  34. package/dist/tools/uiUxDiveTools.js +154 -1
  35. package/dist/tools/uiUxDiveTools.js.map +1 -1
  36. package/dist/toolsetRegistry.js +4 -0
  37. package/dist/toolsetRegistry.js.map +1 -1
  38. package/package.json +2 -2
@@ -0,0 +1,469 @@
1
+ /**
2
+ * Skill Self-Update Protocol — Track rule/memory file provenance,
3
+ * detect staleness via source file hashing, and provide step-by-step
4
+ * resync procedures.
5
+ *
6
+ * A "skill" is any .md rule file (.windsurf/rules/, .cursor/rules/,
7
+ * AGENTS.md, etc.) that an agent uses. Each skill tracks:
8
+ * - Source documents: which files the skill was derived from
9
+ * - Update triggers: conditions that should prompt resyncing
10
+ * - Update instructions: step-by-step procedure to update the skill
11
+ * - Freshness signal: SHA-256 hash of source files + last sync date
12
+ *
13
+ * Frontmatter format injected into skill files:
14
+ * ---
15
+ * skill_id: convex-rules
16
+ * source_files: [convex/schema.ts, package.json]
17
+ * source_hash: abc123...
18
+ * last_synced: 2026-02-11T20:00:00Z
19
+ * update_triggers: [schema changes, new Convex version]
20
+ * update_instructions: [Read schema.ts, Check for new patterns, ...]
21
+ * ---
22
+ */
23
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
24
+ import { createHash } from "node:crypto";
25
+ import { resolve } from "node:path";
26
+ import { getDb, genId } from "../db.js";
27
+ // ── Helpers ─────────────────────────────────────────────────────────
28
+ /** Compute SHA-256 hash of file contents. Returns null if file missing. */
29
+ function hashFile(filePath) {
30
+ try {
31
+ const content = readFileSync(filePath);
32
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ /** Compute composite hash of multiple source files (sorted, concatenated). */
39
+ function computeSourceHash(sourceFiles, projectRoot) {
40
+ const fileHashes = {};
41
+ const parts = [];
42
+ for (const rel of [...sourceFiles].sort()) {
43
+ const abs = resolve(projectRoot, rel);
44
+ const h = hashFile(abs);
45
+ fileHashes[rel] = h;
46
+ parts.push(`${rel}:${h ?? "MISSING"}`);
47
+ }
48
+ const compositeHash = createHash("sha256")
49
+ .update(parts.join("|"))
50
+ .digest("hex")
51
+ .slice(0, 16);
52
+ return { compositeHash, fileHashes };
53
+ }
54
+ /** Parse YAML-like frontmatter from a markdown file. */
55
+ function parseFrontmatter(content) {
56
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
57
+ if (!match)
58
+ return { frontmatter: {}, body: content };
59
+ const fm = {};
60
+ const lines = match[1].split(/\r?\n/);
61
+ for (const line of lines) {
62
+ const kv = line.match(/^(\w[\w_]*)\s*:\s*(.+)$/);
63
+ if (kv) {
64
+ const key = kv[1];
65
+ let val = kv[2].trim();
66
+ // Parse arrays: [a, b, c]
67
+ if (val.startsWith("[") && val.endsWith("]")) {
68
+ val = val.slice(1, -1).split(",").map((s) => s.trim()).filter(Boolean);
69
+ }
70
+ fm[key] = val;
71
+ }
72
+ }
73
+ return { frontmatter: fm, body: match[2] };
74
+ }
75
+ /** Serialize frontmatter back into a markdown file. */
76
+ function serializeFrontmatter(fm, body) {
77
+ const lines = ["---"];
78
+ for (const [key, val] of Object.entries(fm)) {
79
+ if (Array.isArray(val)) {
80
+ lines.push(`${key}: [${val.join(", ")}]`);
81
+ }
82
+ else {
83
+ lines.push(`${key}: ${val}`);
84
+ }
85
+ }
86
+ lines.push("---");
87
+ return lines.join("\n") + "\n" + body;
88
+ }
89
+ /** Find which source files changed between two hashes. */
90
+ function findChangedSources(oldHashes, newHashes) {
91
+ const changed = [];
92
+ for (const [file, newHash] of Object.entries(newHashes)) {
93
+ if (oldHashes[file] !== newHash) {
94
+ changed.push(file);
95
+ }
96
+ }
97
+ return changed;
98
+ }
99
+ // ── Tools ───────────────────────────────────────────────────────────
100
+ export const skillUpdateTools = [
101
+ // ═══════════════════════════════════════════════════════════════════
102
+ // TOOL: register_skill
103
+ // ═══════════════════════════════════════════════════════════════════
104
+ {
105
+ name: "register_skill",
106
+ description: "Register a skill (rule/memory .md file) with its source documents, update triggers, " +
107
+ "and update instructions. Computes a SHA-256 hash of all source files for staleness " +
108
+ "detection. Injects freshness frontmatter into the skill file. Use this when creating " +
109
+ "or adopting a new rule file so it can be automatically checked for staleness.",
110
+ inputSchema: {
111
+ type: "object",
112
+ properties: {
113
+ skillId: {
114
+ type: "string",
115
+ description: "Unique identifier for the skill (e.g. 'convex-rules', 'agents-md', 'nodebench-rules')",
116
+ },
117
+ name: {
118
+ type: "string",
119
+ description: "Human-readable name (e.g. 'Convex Guidelines')",
120
+ },
121
+ filePath: {
122
+ type: "string",
123
+ description: "Path to the skill .md file, relative to project root (e.g. '.windsurf/rules/convexRules.md')",
124
+ },
125
+ description: {
126
+ type: "string",
127
+ description: "What this skill covers",
128
+ },
129
+ sourceFiles: {
130
+ type: "array",
131
+ items: { type: "string" },
132
+ description: "Source files this skill was derived from (relative to project root). e.g. ['convex/schema.ts', 'package.json']",
133
+ },
134
+ updateTriggers: {
135
+ type: "array",
136
+ items: { type: "string" },
137
+ description: "Conditions that should prompt resyncing. e.g. ['schema.ts changes', 'New Convex version in package.json']",
138
+ },
139
+ updateInstructions: {
140
+ type: "array",
141
+ items: { type: "string" },
142
+ description: "Step-by-step procedure to update the skill when stale. e.g. ['Read schema.ts', 'Check for new patterns', 'Update examples']",
143
+ },
144
+ projectRoot: {
145
+ type: "string",
146
+ description: "Absolute path to the project root directory",
147
+ },
148
+ injectFrontmatter: {
149
+ type: "boolean",
150
+ description: "Whether to inject/update freshness frontmatter in the skill file (default: true)",
151
+ default: true,
152
+ },
153
+ },
154
+ required: ["skillId", "name", "filePath", "sourceFiles", "projectRoot"],
155
+ },
156
+ handler: async (args) => {
157
+ const db = getDb();
158
+ const now = new Date().toISOString();
159
+ // Compute source hash
160
+ const { compositeHash, fileHashes } = computeSourceHash(args.sourceFiles, args.projectRoot);
161
+ const missingFiles = Object.entries(fileHashes)
162
+ .filter(([, h]) => h === null)
163
+ .map(([f]) => f);
164
+ // Upsert skill in DB
165
+ const id = genId("skill");
166
+ db.prepare(`
167
+ INSERT INTO skills (id, skill_id, name, file_path, description, source_files, source_hash, update_triggers, update_instructions, last_synced_at, status, metadata, created_at, updated_at)
168
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'fresh', ?, ?, ?)
169
+ ON CONFLICT(skill_id) DO UPDATE SET
170
+ name = excluded.name,
171
+ file_path = excluded.file_path,
172
+ description = excluded.description,
173
+ source_files = excluded.source_files,
174
+ source_hash = excluded.source_hash,
175
+ update_triggers = excluded.update_triggers,
176
+ update_instructions = excluded.update_instructions,
177
+ last_synced_at = excluded.last_synced_at,
178
+ status = 'fresh',
179
+ metadata = excluded.metadata,
180
+ updated_at = excluded.updated_at
181
+ `).run(id, args.skillId, args.name, args.filePath, args.description ?? null, JSON.stringify(args.sourceFiles), compositeHash, JSON.stringify(args.updateTriggers ?? []), JSON.stringify(args.updateInstructions ?? []), now, JSON.stringify({ fileHashes }), now, now);
182
+ // Inject frontmatter into the skill file
183
+ if (args.injectFrontmatter !== false) {
184
+ const absPath = resolve(args.projectRoot, args.filePath);
185
+ if (existsSync(absPath)) {
186
+ const raw = readFileSync(absPath, "utf-8");
187
+ const { frontmatter: existingFm, body } = parseFrontmatter(raw);
188
+ const newFm = {
189
+ ...existingFm,
190
+ skill_id: args.skillId,
191
+ source_files: args.sourceFiles,
192
+ source_hash: compositeHash,
193
+ last_synced: now,
194
+ };
195
+ if (args.updateTriggers?.length) {
196
+ newFm.update_triggers = args.updateTriggers;
197
+ }
198
+ if (args.updateInstructions?.length) {
199
+ newFm.update_instructions = args.updateInstructions;
200
+ }
201
+ writeFileSync(absPath, serializeFrontmatter(newFm, body), "utf-8");
202
+ }
203
+ }
204
+ // Record initial sync in history
205
+ db.prepare(`
206
+ INSERT INTO skill_sync_history (id, skill_id, previous_hash, new_hash, changed_sources, trigger_reason, sync_notes, synced_at)
207
+ VALUES (?, ?, NULL, ?, ?, 'initial_registration', 'Skill registered', ?)
208
+ `).run(genId("sync"), args.skillId, compositeHash, JSON.stringify(args.sourceFiles), now);
209
+ return {
210
+ skillId: args.skillId,
211
+ name: args.name,
212
+ filePath: args.filePath,
213
+ sourceFiles: args.sourceFiles,
214
+ sourceHash: compositeHash,
215
+ missingFiles,
216
+ status: "fresh",
217
+ lastSyncedAt: now,
218
+ frontmatterInjected: args.injectFrontmatter !== false,
219
+ _hint: `Skill "${args.name}" registered with ${args.sourceFiles.length} source files. Hash: ${compositeHash}. Use check_skill_freshness to detect staleness.`,
220
+ };
221
+ },
222
+ },
223
+ // ═══════════════════════════════════════════════════════════════════
224
+ // TOOL: check_skill_freshness
225
+ // ═══════════════════════════════════════════════════════════════════
226
+ {
227
+ name: "check_skill_freshness",
228
+ description: "Check if registered skills are stale by comparing current source file hashes " +
229
+ "against stored hashes. Returns a freshness report for each skill, identifying " +
230
+ "which source files changed and which update triggers apply. Run this at the " +
231
+ "start of a session or after significant code changes.",
232
+ inputSchema: {
233
+ type: "object",
234
+ properties: {
235
+ skillId: {
236
+ type: "string",
237
+ description: "Check a specific skill (optional — omit to check all)",
238
+ },
239
+ projectRoot: {
240
+ type: "string",
241
+ description: "Absolute path to the project root directory",
242
+ },
243
+ autoUpdateStatus: {
244
+ type: "boolean",
245
+ description: "Automatically update skill status in DB (default: true)",
246
+ default: true,
247
+ },
248
+ },
249
+ required: ["projectRoot"],
250
+ },
251
+ handler: async (args) => {
252
+ const db = getDb();
253
+ const skills = args.skillId
254
+ ? db.prepare("SELECT * FROM skills WHERE skill_id = ?").all(args.skillId)
255
+ : db.prepare("SELECT * FROM skills ORDER BY skill_id").all();
256
+ if (!skills.length) {
257
+ return {
258
+ count: 0,
259
+ skills: [],
260
+ _hint: args.skillId
261
+ ? `No skill found with id "${args.skillId}". Use register_skill to register it.`
262
+ : "No skills registered. Use register_skill to register your rule files.",
263
+ };
264
+ }
265
+ const report = [];
266
+ let staleCount = 0;
267
+ for (const skill of skills) {
268
+ const sourceFiles = JSON.parse(skill.source_files);
269
+ const storedHash = skill.source_hash;
270
+ const storedMeta = skill.metadata ? JSON.parse(skill.metadata) : {};
271
+ const storedFileHashes = storedMeta.fileHashes ?? {};
272
+ const { compositeHash, fileHashes } = computeSourceHash(sourceFiles, args.projectRoot);
273
+ const isStale = compositeHash !== storedHash;
274
+ const changedFiles = findChangedSources(storedFileHashes, fileHashes);
275
+ const triggers = JSON.parse(skill.update_triggers);
276
+ const instructions = JSON.parse(skill.update_instructions);
277
+ // Check which triggers apply based on changed files
278
+ const matchedTriggers = triggers.filter(t => {
279
+ const tLower = t.toLowerCase();
280
+ return changedFiles.some(f => tLower.includes(f.toLowerCase().split("/").pop().split(".")[0]));
281
+ });
282
+ if (isStale)
283
+ staleCount++;
284
+ // Update DB status
285
+ if (args.autoUpdateStatus !== false && isStale) {
286
+ db.prepare("UPDATE skills SET status = 'stale', updated_at = datetime('now') WHERE skill_id = ?")
287
+ .run(skill.skill_id);
288
+ }
289
+ const lastSyncMs = skill.last_synced_at ? Date.now() - new Date(skill.last_synced_at).getTime() : null;
290
+ const daysSinceSync = lastSyncMs ? Math.floor(lastSyncMs / 86400000) : null;
291
+ report.push({
292
+ skillId: skill.skill_id,
293
+ name: skill.name,
294
+ filePath: skill.file_path,
295
+ status: isStale ? "stale" : "fresh",
296
+ storedHash,
297
+ currentHash: compositeHash,
298
+ changedFiles,
299
+ matchedTriggers,
300
+ lastSyncedAt: skill.last_synced_at,
301
+ daysSinceSync,
302
+ sourceFileCount: sourceFiles.length,
303
+ updateInstructions: isStale ? instructions : undefined,
304
+ });
305
+ }
306
+ return {
307
+ count: report.length,
308
+ staleCount,
309
+ freshCount: report.length - staleCount,
310
+ skills: report,
311
+ _hint: staleCount > 0
312
+ ? `${staleCount} skill(s) are STALE and need resyncing. Use sync_skill({ skillId, projectRoot }) to update each one.`
313
+ : "All skills are fresh — no updates needed.",
314
+ };
315
+ },
316
+ },
317
+ // ═══════════════════════════════════════════════════════════════════
318
+ // TOOL: sync_skill
319
+ // ═══════════════════════════════════════════════════════════════════
320
+ {
321
+ name: "sync_skill",
322
+ description: "Resync a stale skill after applying updates. Recomputes source hashes, updates " +
323
+ "the freshness frontmatter in the skill file, and records the sync in history. " +
324
+ "Call this AFTER you have followed the update_instructions and updated the skill " +
325
+ "file content. This tool just records that the sync happened.",
326
+ inputSchema: {
327
+ type: "object",
328
+ properties: {
329
+ skillId: {
330
+ type: "string",
331
+ description: "The skill to mark as synced",
332
+ },
333
+ projectRoot: {
334
+ type: "string",
335
+ description: "Absolute path to the project root directory",
336
+ },
337
+ syncNotes: {
338
+ type: "string",
339
+ description: "What was updated in this sync (e.g. 'Added new table validators, updated function patterns')",
340
+ },
341
+ triggerReason: {
342
+ type: "string",
343
+ description: "What triggered this sync (e.g. 'schema.ts changed — new narrativeHypotheses table')",
344
+ },
345
+ },
346
+ required: ["skillId", "projectRoot"],
347
+ },
348
+ handler: async (args) => {
349
+ const db = getDb();
350
+ const now = new Date().toISOString();
351
+ const skill = db.prepare("SELECT * FROM skills WHERE skill_id = ?").get(args.skillId);
352
+ if (!skill)
353
+ throw new Error(`Skill "${args.skillId}" not found. Use register_skill first.`);
354
+ const sourceFiles = JSON.parse(skill.source_files);
355
+ const previousHash = skill.source_hash;
356
+ const previousMeta = skill.metadata ? JSON.parse(skill.metadata) : {};
357
+ const previousFileHashes = previousMeta.fileHashes ?? {};
358
+ // Recompute hash
359
+ const { compositeHash, fileHashes } = computeSourceHash(sourceFiles, args.projectRoot);
360
+ const changedFiles = findChangedSources(previousFileHashes, fileHashes);
361
+ // Update skill in DB
362
+ db.prepare(`
363
+ UPDATE skills SET
364
+ source_hash = ?,
365
+ last_synced_at = ?,
366
+ status = 'fresh',
367
+ metadata = ?,
368
+ updated_at = ?
369
+ WHERE skill_id = ?
370
+ `).run(compositeHash, now, JSON.stringify({ fileHashes }), now, args.skillId);
371
+ // Record in history
372
+ db.prepare(`
373
+ INSERT INTO skill_sync_history (id, skill_id, previous_hash, new_hash, changed_sources, trigger_reason, sync_notes, synced_at)
374
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
375
+ `).run(genId("sync"), args.skillId, previousHash, compositeHash, JSON.stringify(changedFiles), args.triggerReason ?? null, args.syncNotes ?? null, now);
376
+ // Update frontmatter in skill file
377
+ const absPath = resolve(args.projectRoot, skill.file_path);
378
+ if (existsSync(absPath)) {
379
+ const raw = readFileSync(absPath, "utf-8");
380
+ const { frontmatter: existingFm, body } = parseFrontmatter(raw);
381
+ existingFm.source_hash = compositeHash;
382
+ existingFm.last_synced = now;
383
+ writeFileSync(absPath, serializeFrontmatter(existingFm, body), "utf-8");
384
+ }
385
+ return {
386
+ skillId: args.skillId,
387
+ name: skill.name,
388
+ previousHash,
389
+ newHash: compositeHash,
390
+ changedFiles,
391
+ status: "fresh",
392
+ syncedAt: now,
393
+ triggerReason: args.triggerReason ?? null,
394
+ syncNotes: args.syncNotes ?? null,
395
+ _hint: `Skill "${skill.name}" synced. Hash: ${previousHash} → ${compositeHash}. ${changedFiles.length} source file(s) changed.`,
396
+ };
397
+ },
398
+ },
399
+ // ═══════════════════════════════════════════════════════════════════
400
+ // TOOL: list_skills
401
+ // ═══════════════════════════════════════════════════════════════════
402
+ {
403
+ name: "list_skills",
404
+ description: "List all registered skills with their freshness status, source files, " +
405
+ "update triggers, and sync history. Use to get an overview of all tracked " +
406
+ "rule/memory files and whether any need updating.",
407
+ inputSchema: {
408
+ type: "object",
409
+ properties: {
410
+ status: {
411
+ type: "string",
412
+ enum: ["all", "fresh", "stale"],
413
+ description: "Filter by status (default: all)",
414
+ },
415
+ includeHistory: {
416
+ type: "boolean",
417
+ description: "Include sync history for each skill (default: false)",
418
+ },
419
+ },
420
+ },
421
+ handler: async (args) => {
422
+ const db = getDb();
423
+ const filter = args.status && args.status !== "all" ? args.status : null;
424
+ const skills = filter
425
+ ? db.prepare("SELECT * FROM skills WHERE status = ? ORDER BY skill_id").all(filter)
426
+ : db.prepare("SELECT * FROM skills ORDER BY skill_id").all();
427
+ const result = skills.map(s => {
428
+ const entry = {
429
+ skillId: s.skill_id,
430
+ name: s.name,
431
+ filePath: s.file_path,
432
+ description: s.description,
433
+ status: s.status,
434
+ sourceFiles: JSON.parse(s.source_files),
435
+ sourceHash: s.source_hash,
436
+ updateTriggers: JSON.parse(s.update_triggers),
437
+ updateInstructions: JSON.parse(s.update_instructions),
438
+ lastSyncedAt: s.last_synced_at,
439
+ createdAt: s.created_at,
440
+ };
441
+ if (args.includeHistory) {
442
+ const history = db.prepare("SELECT * FROM skill_sync_history WHERE skill_id = ? ORDER BY synced_at DESC LIMIT 10").all(s.skill_id);
443
+ entry.syncHistory = history.map(h => ({
444
+ previousHash: h.previous_hash,
445
+ newHash: h.new_hash,
446
+ changedSources: h.changed_sources ? JSON.parse(h.changed_sources) : [],
447
+ triggerReason: h.trigger_reason,
448
+ syncNotes: h.sync_notes,
449
+ syncedAt: h.synced_at,
450
+ }));
451
+ }
452
+ return entry;
453
+ });
454
+ const staleCount = result.filter(s => s.status === "stale").length;
455
+ return {
456
+ count: result.length,
457
+ staleCount,
458
+ freshCount: result.length - staleCount,
459
+ skills: result,
460
+ _hint: staleCount > 0
461
+ ? `${staleCount} skill(s) are stale. Run check_skill_freshness to see details, then sync_skill to update.`
462
+ : result.length > 0
463
+ ? "All skills are fresh."
464
+ : "No skills registered. Use register_skill to start tracking your rule files.",
465
+ };
466
+ },
467
+ },
468
+ ];
469
+ //# sourceMappingURL=skillUpdateTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skillUpdateTools.js","sourceRoot":"","sources":["../../src/tools/skillUpdateTools.ts"],"names":[],"mappings":"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"}
@@ -12,8 +12,13 @@
12
12
  export interface ToolQuickRef {
13
13
  /** 1-2 sentence guidance on what to do after calling this tool */
14
14
  nextAction: string;
15
- /** Tools commonly used after this one */
15
+ /** Tools commonly used after this one (workflow-sequential adjacency) */
16
16
  nextTools: string[];
17
+ /** Conceptually related tools — same problem domain but different workflow paths.
18
+ * Unlike nextTools (sequential: "do X then Y"), relatedTools is associative:
19
+ * "if you're doing X, you might also want Y". Auto-derived from category siblings,
20
+ * domain clusters, and tag overlap. Enables multi-hop graph traversal. */
21
+ relatedTools?: string[];
17
22
  /** Which methodology to consult for full guidance */
18
23
  methodology?: string;
19
24
  /** Short tip for effective use */
@@ -33,6 +38,9 @@ export interface ToolRegistryEntry {
33
38
  export declare const TOOL_REGISTRY: Map<string, ToolRegistryEntry>;
34
39
  /** All registry entries as array */
35
40
  export declare const ALL_REGISTRY_ENTRIES: ToolRegistryEntry[];
41
+ export declare function _setDomainClustersRef(clusters: Record<string, string[]>): void;
42
+ /** Populate relatedTools for all registry entries. Called once at module load after DOMAIN_CLUSTERS exists. */
43
+ export declare function _populateRelatedTools(): void;
36
44
  /** Get quick ref for a tool, with fallback for unregistered tools */
37
45
  export declare function getQuickRef(toolName: string): ToolQuickRef | null;
38
46
  /** Get all tools in a category */
@@ -51,6 +59,10 @@ export interface SearchResult {
51
59
  quickRef: ToolQuickRef;
52
60
  phase: string;
53
61
  tags: string[];
62
+ /** Depth at which this result was found (0 = direct match, 1+ = expansion hop) */
63
+ depth?: number;
64
+ /** Tools that led to this result being included via relatedTools expansion */
65
+ expandedFrom?: string[];
54
66
  }
55
67
  export type SearchMode = "hybrid" | "fuzzy" | "regex" | "prefix" | "semantic" | "exact" | "dense" | "embedding";
56
68
  /** Tokenize text into lowercase words (alpha + underscore only) */
@@ -108,6 +120,8 @@ export declare function hybridSearch(query: string, tools: Array<{
108
120
  /** If true, search ALL_REGISTRY_ENTRIES (full 175-tool registry) regardless of loaded preset.
109
121
  * Needed for dynamic loading: discover_tools must find unloaded tools to suggest load_toolset. */
110
122
  searchFullRegistry?: boolean;
123
+ /** Number of results to skip for cursor-based pagination. Default: 0. */
124
+ offset?: number;
111
125
  /** Ablation flags: disable individual strategies to measure their contribution */
112
126
  ablation?: {
113
127
  disableSynonyms?: boolean;