kirograph 0.14.1 → 0.16.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/LICENSE +21 -0
- package/README.md +239 -20
- package/dist/assets/logo.png +0 -0
- package/dist/bin/commands/docs.js +357 -0
- package/dist/bin/commands/docs.js.map +7 -0
- package/dist/bin/commands/help.js +3 -0
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/uninit.js +10 -13
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/installer/config-prompt.js +53 -23
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/hooks.js +20 -1
- package/dist/bin/installer/hooks.js.map +2 -2
- package/dist/bin/installer/index.js +14 -4
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/prompts.js +37 -6
- package/dist/bin/installer/prompts.js.map +2 -2
- package/dist/bin/installer/steering.js +40 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/aider.js +72 -0
- package/dist/bin/installer/targets/aider.js.map +7 -0
- package/dist/bin/installer/targets/amp.js +91 -0
- package/dist/bin/installer/targets/amp.js.map +7 -0
- package/dist/bin/installer/targets/antigravity.js +109 -0
- package/dist/bin/installer/targets/antigravity.js.map +7 -0
- package/dist/bin/installer/targets/augment.js +81 -0
- package/dist/bin/installer/targets/augment.js.map +7 -0
- package/dist/bin/installer/targets/claude.js +1 -1
- package/dist/bin/installer/targets/claude.js.map +2 -2
- package/dist/bin/installer/targets/cline.js +91 -0
- package/dist/bin/installer/targets/cline.js.map +7 -0
- package/dist/bin/installer/targets/codex.js +1 -1
- package/dist/bin/installer/targets/codex.js.map +2 -2
- package/dist/bin/installer/targets/continue.js +107 -0
- package/dist/bin/installer/targets/continue.js.map +7 -0
- package/dist/bin/installer/targets/copilot.js +123 -0
- package/dist/bin/installer/targets/copilot.js.map +7 -0
- package/dist/bin/installer/targets/cursor.js +143 -0
- package/dist/bin/installer/targets/cursor.js.map +7 -0
- package/dist/bin/installer/targets/devin.js +148 -0
- package/dist/bin/installer/targets/devin.js.map +7 -0
- package/dist/bin/installer/targets/gemini-cli.js +126 -0
- package/dist/bin/installer/targets/gemini-cli.js.map +7 -0
- package/dist/bin/installer/targets/generic.js +120 -0
- package/dist/bin/installer/targets/generic.js.map +7 -0
- package/dist/bin/installer/targets/goose.js +72 -0
- package/dist/bin/installer/targets/goose.js.map +7 -0
- package/dist/bin/installer/targets/index.js.map +1 -1
- package/dist/bin/installer/targets/junie.js +105 -0
- package/dist/bin/installer/targets/junie.js.map +7 -0
- package/dist/bin/installer/targets/kilo.js +122 -0
- package/dist/bin/installer/targets/kilo.js.map +7 -0
- package/dist/bin/installer/targets/kiro.js +3 -3
- package/dist/bin/installer/targets/kiro.js.map +2 -2
- package/dist/bin/installer/targets/opencode.js +135 -0
- package/dist/bin/installer/targets/opencode.js.map +7 -0
- package/dist/bin/installer/targets/openhands.js +90 -0
- package/dist/bin/installer/targets/openhands.js.map +7 -0
- package/dist/bin/installer/targets/replit.js +72 -0
- package/dist/bin/installer/targets/replit.js.map +7 -0
- package/dist/bin/installer/targets/roo.js +96 -0
- package/dist/bin/installer/targets/roo.js.map +7 -0
- package/dist/bin/installer/targets/tabnine.js +82 -0
- package/dist/bin/installer/targets/tabnine.js.map +7 -0
- package/dist/bin/installer/targets/trae.js +84 -0
- package/dist/bin/installer/targets/trae.js.map +7 -0
- package/dist/bin/installer/targets/warp.js +97 -0
- package/dist/bin/installer/targets/warp.js.map +7 -0
- package/dist/bin/installer/targets/windsurf.js +141 -0
- package/dist/bin/installer/targets/windsurf.js.map +7 -0
- package/dist/bin/kirograph.js +5 -1
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/compression/naive-cost.js +33 -0
- package/dist/compression/naive-cost.js.map +2 -2
- package/dist/compression/tracker.js +27 -4
- package/dist/compression/tracker.js.map +2 -2
- package/dist/compression/types.js.map +1 -1
- package/dist/config.js +66 -1
- package/dist/config.js.map +2 -2
- package/dist/core/pipeline.js +23 -0
- package/dist/core/pipeline.js.map +2 -2
- package/dist/db/database.js +28 -0
- package/dist/db/database.js.map +2 -2
- package/dist/db/docs-schema.sql +50 -0
- package/dist/docs/formats/asciidoc.js +108 -0
- package/dist/docs/formats/asciidoc.js.map +7 -0
- package/dist/docs/formats/html.js +100 -0
- package/dist/docs/formats/html.js.map +7 -0
- package/dist/docs/formats/index.js +81 -0
- package/dist/docs/formats/index.js.map +7 -0
- package/dist/docs/formats/markdown.js +146 -0
- package/dist/docs/formats/markdown.js.map +7 -0
- package/dist/docs/formats/openapi.js +228 -0
- package/dist/docs/formats/openapi.js.map +7 -0
- package/dist/docs/formats/org.js +117 -0
- package/dist/docs/formats/org.js.map +7 -0
- package/dist/docs/formats/plaintext.js +119 -0
- package/dist/docs/formats/plaintext.js.map +7 -0
- package/dist/docs/formats/rdoc.js +105 -0
- package/dist/docs/formats/rdoc.js.map +7 -0
- package/dist/docs/formats/rst.js +121 -0
- package/dist/docs/formats/rst.js.map +7 -0
- package/dist/docs/indexer.js +340 -0
- package/dist/docs/indexer.js.map +7 -0
- package/dist/docs/linker.js +151 -0
- package/dist/docs/linker.js.map +7 -0
- package/dist/docs/lint.js +92 -0
- package/dist/docs/lint.js.map +7 -0
- package/dist/docs/queries.js +295 -0
- package/dist/docs/queries.js.map +7 -0
- package/dist/docs/section-id.js +57 -0
- package/dist/docs/section-id.js.map +7 -0
- package/dist/docs/summarizer.js +55 -0
- package/dist/docs/summarizer.js.map +7 -0
- package/dist/docs/types.js +17 -0
- package/dist/docs/types.js.map +7 -0
- package/dist/docs/vectors.js +217 -0
- package/dist/docs/vectors.js.map +7 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/mcp/tool-names.js +10 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.js +476 -3
- package/dist/mcp/tools.js.map +2 -2
- package/package.json +1 -1
package/dist/mcp/tools.js
CHANGED
|
@@ -61,6 +61,19 @@ function writeSessionMarker(projectRoot) {
|
|
|
61
61
|
} catch {
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
function formatAge(timestamp) {
|
|
65
|
+
const diff = Date.now() - timestamp;
|
|
66
|
+
const minutes = Math.floor(diff / 6e4);
|
|
67
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
68
|
+
const hours = Math.floor(minutes / 60);
|
|
69
|
+
if (hours < 24) return `${hours}h ago`;
|
|
70
|
+
const days = Math.floor(hours / 24);
|
|
71
|
+
if (days < 7) return `${days}d ago`;
|
|
72
|
+
const weeks = Math.floor(days / 7);
|
|
73
|
+
if (weeks < 5) return `${weeks}w ago`;
|
|
74
|
+
const months = Math.floor(days / 30);
|
|
75
|
+
return `${months}mo ago`;
|
|
76
|
+
}
|
|
64
77
|
const tools = [
|
|
65
78
|
{
|
|
66
79
|
name: "kirograph_search",
|
|
@@ -343,6 +356,130 @@ const tools = [
|
|
|
343
356
|
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
344
357
|
}
|
|
345
358
|
}
|
|
359
|
+
},
|
|
360
|
+
// ── Memory tools (require enableMemory=true) ────────────────────────────────
|
|
361
|
+
{
|
|
362
|
+
name: "kirograph_mem_search",
|
|
363
|
+
description: "Search project memory for past decisions, errors, patterns, and context. Returns observations ranked by relevance.",
|
|
364
|
+
inputSchema: {
|
|
365
|
+
type: "object",
|
|
366
|
+
properties: {
|
|
367
|
+
query: { type: "string", description: "Natural language search query" },
|
|
368
|
+
kind: {
|
|
369
|
+
type: "string",
|
|
370
|
+
description: "Filter by observation kind",
|
|
371
|
+
enum: ["decision", "error", "pattern", "architecture", "summary", "note"]
|
|
372
|
+
},
|
|
373
|
+
limit: { type: "number", description: "Max results (default: 10)", default: 10 },
|
|
374
|
+
sessionId: { type: "string", description: "Filter to specific session" },
|
|
375
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
376
|
+
},
|
|
377
|
+
required: ["query"]
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: "kirograph_mem_store",
|
|
382
|
+
description: "Store an observation in project memory. Content is automatically compressed (if caveman mode is on) and linked to relevant code symbols.",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {
|
|
386
|
+
content: { type: "string", description: "Observation text" },
|
|
387
|
+
kind: {
|
|
388
|
+
type: "string",
|
|
389
|
+
description: "Observation kind",
|
|
390
|
+
enum: ["decision", "error", "pattern", "architecture", "summary", "note"],
|
|
391
|
+
default: "note"
|
|
392
|
+
},
|
|
393
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
394
|
+
},
|
|
395
|
+
required: ["content"]
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "kirograph_mem_timeline",
|
|
400
|
+
description: "List recent sessions and their observations chronologically.",
|
|
401
|
+
inputSchema: {
|
|
402
|
+
type: "object",
|
|
403
|
+
properties: {
|
|
404
|
+
limit: { type: "number", description: "Number of sessions to show (default: 5)", default: 5 },
|
|
405
|
+
sessionId: { type: "string", description: "Show observations for a specific session" },
|
|
406
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
name: "kirograph_mem_status",
|
|
412
|
+
description: "Memory subsystem health: session count, observations, embedding coverage, storage size.",
|
|
413
|
+
inputSchema: {
|
|
414
|
+
type: "object",
|
|
415
|
+
properties: {
|
|
416
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
// ── Docs tools (require enableDocs=true) ────────────────────────────────────
|
|
421
|
+
{
|
|
422
|
+
name: "kirograph_docs_toc",
|
|
423
|
+
description: "Get table of contents for a documentation file or the whole project. Returns section IDs, titles, levels, and summaries.",
|
|
424
|
+
inputSchema: {
|
|
425
|
+
type: "object",
|
|
426
|
+
properties: {
|
|
427
|
+
file: { type: "string", description: "Filter to a specific doc file (relative path). Omit for project-wide TOC." },
|
|
428
|
+
tree: { type: "boolean", description: "Return nested tree structure (default: false, flat list)", default: false },
|
|
429
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
name: "kirograph_docs_search",
|
|
435
|
+
description: "Search documentation sections by query. Returns matching sections ranked by relevance. Independent from kirograph_search (code-only).",
|
|
436
|
+
inputSchema: {
|
|
437
|
+
type: "object",
|
|
438
|
+
properties: {
|
|
439
|
+
query: { type: "string", description: "Search query (natural language or keywords)" },
|
|
440
|
+
file: { type: "string", description: "Narrow search to a specific doc file (relative path)" },
|
|
441
|
+
limit: { type: "number", description: "Max results (default: 10)", default: 10 },
|
|
442
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
443
|
+
},
|
|
444
|
+
required: ["query"]
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "kirograph_docs_section",
|
|
449
|
+
description: "Retrieve full content of a documentation section by its stable ID. Use context=true to also get ancestor headings and child summaries.",
|
|
450
|
+
inputSchema: {
|
|
451
|
+
type: "object",
|
|
452
|
+
properties: {
|
|
453
|
+
id: { type: "string", description: "Section ID (from kirograph_docs_toc or kirograph_docs_search results)" },
|
|
454
|
+
context: { type: "boolean", description: "Include ancestor heading chain and child summaries (default: false)", default: false },
|
|
455
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
456
|
+
},
|
|
457
|
+
required: ["id"]
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: "kirograph_docs_outline",
|
|
462
|
+
description: "Get the heading hierarchy for a single documentation file. Lighter than full TOC when you know which file is relevant.",
|
|
463
|
+
inputSchema: {
|
|
464
|
+
type: "object",
|
|
465
|
+
properties: {
|
|
466
|
+
file: { type: "string", description: "Relative path to the doc file" },
|
|
467
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
468
|
+
},
|
|
469
|
+
required: ["file"]
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: "kirograph_docs_refs",
|
|
474
|
+
description: "Find code symbols referenced by a doc section, or doc sections that reference a code symbol. Bidirectional lookup.",
|
|
475
|
+
inputSchema: {
|
|
476
|
+
type: "object",
|
|
477
|
+
properties: {
|
|
478
|
+
sectionId: { type: "string", description: "Doc section ID (find code symbols it references)" },
|
|
479
|
+
nodeId: { type: "string", description: "Code symbol qualified name (find doc sections that reference it)" },
|
|
480
|
+
projectPath: { type: "string", description: "Project root path (optional)" }
|
|
481
|
+
}
|
|
482
|
+
}
|
|
346
483
|
}
|
|
347
484
|
];
|
|
348
485
|
class ToolHandler {
|
|
@@ -388,7 +525,13 @@ class ToolHandler {
|
|
|
388
525
|
const naiveCost = estimateNaiveCost(toolName, outputTokens, args);
|
|
389
526
|
if (naiveCost !== null && naiveCost > outputTokens) {
|
|
390
527
|
const tracker = new import_tracker.TokenTracker(projectRoot);
|
|
391
|
-
|
|
528
|
+
if (toolName.startsWith("kirograph_mem_")) {
|
|
529
|
+
tracker.recordMemorySaving(toolName, outputTokens, naiveCost);
|
|
530
|
+
} else if (toolName.startsWith("kirograph_docs_")) {
|
|
531
|
+
tracker.recordDocsSaving(toolName, outputTokens, naiveCost);
|
|
532
|
+
} else {
|
|
533
|
+
tracker.recordGraphSaving(toolName, outputTokens, naiveCost);
|
|
534
|
+
}
|
|
392
535
|
}
|
|
393
536
|
} catch {
|
|
394
537
|
}
|
|
@@ -455,14 +598,20 @@ class ToolHandler {
|
|
|
455
598
|
` Tokens with KiroGraph: ~${stats.totalCompressed.toLocaleString()}`,
|
|
456
599
|
` Saved: ${stats.totalSaved.toLocaleString()} tokens (${stats.savingsPercent}%)`
|
|
457
600
|
];
|
|
458
|
-
if (stats.bySource.exec.count > 0 || stats.bySource.graph.count > 0) {
|
|
601
|
+
if (stats.bySource.exec.count > 0 || stats.bySource.graph.count > 0 || stats.bySource.memory.count > 0 || stats.bySource.docs.count > 0) {
|
|
459
602
|
lines.push("", "By source:");
|
|
460
603
|
if (stats.bySource.graph.count > 0) {
|
|
461
604
|
lines.push(` Graph tools: ${stats.bySource.graph.count} calls, ~${stats.bySource.graph.saved.toLocaleString()} tokens saved (vs file reads/grep)`);
|
|
462
605
|
}
|
|
606
|
+
if (stats.bySource.docs.count > 0) {
|
|
607
|
+
lines.push(` Docs tools: ${stats.bySource.docs.count} calls, ~${stats.bySource.docs.saved.toLocaleString()} tokens saved (vs reading full doc files)`);
|
|
608
|
+
}
|
|
463
609
|
if (stats.bySource.exec.count > 0) {
|
|
464
610
|
lines.push(` Compression: ${stats.bySource.exec.count} calls, ~${stats.bySource.exec.saved.toLocaleString()} tokens saved (vs raw output)`);
|
|
465
611
|
}
|
|
612
|
+
if (stats.bySource.memory.count > 0) {
|
|
613
|
+
lines.push(` Memory: ${stats.bySource.memory.count} calls, ~${stats.bySource.memory.saved.toLocaleString()} tokens saved (vs re-discovering context)`);
|
|
614
|
+
}
|
|
466
615
|
}
|
|
467
616
|
if (Object.keys(stats.byFamily).length > 0) {
|
|
468
617
|
lines.push("", "Top families:");
|
|
@@ -520,6 +669,69 @@ class ToolHandler {
|
|
|
520
669
|
}
|
|
521
670
|
}
|
|
522
671
|
}
|
|
672
|
+
try {
|
|
673
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
674
|
+
const projectRoot = cg.getProjectRoot();
|
|
675
|
+
const config = await loadConfig(projectRoot);
|
|
676
|
+
if (config.enableMemory) {
|
|
677
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
678
|
+
const db = cg.getDatabase();
|
|
679
|
+
db.applyMemorySchema();
|
|
680
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
681
|
+
mem.initialize();
|
|
682
|
+
const qualifiedNames = [
|
|
683
|
+
...ctx.entryPoints.map((n) => n.qualifiedName),
|
|
684
|
+
...ctx.relatedNodes.slice(0, 5).map((n) => n.qualifiedName)
|
|
685
|
+
].filter(Boolean);
|
|
686
|
+
const contextLimit = config.memoryContextLimit ?? 3;
|
|
687
|
+
const contextThreshold = config.memoryContextThreshold ?? 0.3;
|
|
688
|
+
let memResults = mem.getLinkedObservations(qualifiedNames, contextLimit, contextThreshold);
|
|
689
|
+
if (memResults.length === 0) {
|
|
690
|
+
memResults = (await mem.search(args.task, { limit: contextLimit })).filter((r) => r.score >= contextThreshold);
|
|
691
|
+
}
|
|
692
|
+
if (memResults.length > 0) {
|
|
693
|
+
lines.push("", "## Related Memory");
|
|
694
|
+
for (const r of memResults.slice(0, contextLimit)) {
|
|
695
|
+
const age = formatAge(r.observation.createdAt);
|
|
696
|
+
lines.push(`- [${r.observation.kind}] ${r.observation.content} (${age})`);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
} catch {
|
|
701
|
+
}
|
|
702
|
+
try {
|
|
703
|
+
const projectRoot2 = cg.getProjectRoot();
|
|
704
|
+
const config2 = await (await Promise.resolve().then(() => require("../config.js"))).loadConfig(projectRoot2);
|
|
705
|
+
if (config2.enableDocs && config2.docsContextLimit > 0) {
|
|
706
|
+
const db2 = cg.getDatabase();
|
|
707
|
+
db2.applyDocsSchema();
|
|
708
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
709
|
+
const docsQueries = new DocsQueries(db2.getRawDb(), projectRoot2);
|
|
710
|
+
const qNames = ctx.entryPoints.map((n) => n.qualifiedName).filter(Boolean);
|
|
711
|
+
if (qNames.length > 0) {
|
|
712
|
+
const docRefs = docsQueries.getRefs({ qualifiedName: qNames[0] });
|
|
713
|
+
const additionalRefs = qNames.slice(1, 5).flatMap((qn) => docsQueries.getRefs({ qualifiedName: qn }));
|
|
714
|
+
const allDocRefs = [...docRefs, ...additionalRefs];
|
|
715
|
+
const seenSections = /* @__PURE__ */ new Set();
|
|
716
|
+
const uniqueRefs = allDocRefs.filter((r) => {
|
|
717
|
+
if (seenSections.has(r.sectionId)) return false;
|
|
718
|
+
seenSections.add(r.sectionId);
|
|
719
|
+
return r.confidence >= config2.docsContextThreshold;
|
|
720
|
+
}).slice(0, config2.docsContextLimit);
|
|
721
|
+
if (uniqueRefs.length > 0) {
|
|
722
|
+
lines.push("", "## Related Documentation");
|
|
723
|
+
for (const ref of uniqueRefs) {
|
|
724
|
+
const section = docsQueries.getSection(ref.sectionId);
|
|
725
|
+
if (section) {
|
|
726
|
+
const summary = section.section.summary ?? section.section.title;
|
|
727
|
+
lines.push(`- [${ref.refType}] ${summary} \u2014 ${section.section.filePath} (ID: ${ref.sectionId})`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
} catch {
|
|
734
|
+
}
|
|
523
735
|
return lines.join("\n");
|
|
524
736
|
}
|
|
525
737
|
case "kirograph_callers": {
|
|
@@ -552,8 +764,37 @@ class ToolHandler {
|
|
|
552
764
|
const node = results[0].node;
|
|
553
765
|
const affected = await cg.getImpactRadius(node.id, args.depth ?? 2);
|
|
554
766
|
if (affected.length === 0) return `No dependents found for \`${node.name}\`.`;
|
|
555
|
-
|
|
767
|
+
let output = `Changing \`${node.name}\` may affect ${affected.length} symbol(s):
|
|
556
768
|
` + affected.map((n) => `- ${mapKind(n.kind)} \`${n.name}\` \u2014 ${n.filePath}:${n.startLine}`).join("\n");
|
|
769
|
+
try {
|
|
770
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
771
|
+
const projectRoot = cg.getProjectRoot();
|
|
772
|
+
const config = await loadConfig(projectRoot);
|
|
773
|
+
if (config.enableMemory) {
|
|
774
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
775
|
+
const db = cg.getDatabase();
|
|
776
|
+
db.applyMemorySchema();
|
|
777
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
778
|
+
mem.initialize();
|
|
779
|
+
const contextLimit = config.memoryContextLimit ?? 3;
|
|
780
|
+
const contextThreshold = config.memoryContextThreshold ?? 0.3;
|
|
781
|
+
const memResults = mem.getLinkedObservations(
|
|
782
|
+
[node.qualifiedName],
|
|
783
|
+
contextLimit,
|
|
784
|
+
contextThreshold
|
|
785
|
+
);
|
|
786
|
+
if (memResults.length > 0) {
|
|
787
|
+
output += "\n\nRelated Memory:";
|
|
788
|
+
for (const r of memResults) {
|
|
789
|
+
const age = formatAge(r.observation.createdAt);
|
|
790
|
+
output += `
|
|
791
|
+
- [${r.observation.kind}] ${r.observation.content} (${age})`;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
} catch {
|
|
796
|
+
}
|
|
797
|
+
return output;
|
|
557
798
|
}
|
|
558
799
|
case "kirograph_node": {
|
|
559
800
|
const results = cg.searchNodes(args.symbol, void 0, 5);
|
|
@@ -585,6 +826,21 @@ class ToolHandler {
|
|
|
585
826
|
] : [` Semantic search: disabled`];
|
|
586
827
|
const frameworkLine = stats.frameworks.length > 0 ? ` Frameworks: ${stats.frameworks.join(", ")}` : ` Frameworks: none detected`;
|
|
587
828
|
const archLine = stats.architectureEnabled ? stats.architectureStats ? ` Architecture: enabled \u2014 ${stats.architectureStats.packages} packages, ${stats.architectureStats.layers} layers, ${stats.architectureStats.packageDeps} deps` : ` Architecture: enabled (not yet analyzed \u2014 run kirograph index)` : ` Architecture: disabled`;
|
|
829
|
+
let docsLine = " Documentation: disabled";
|
|
830
|
+
try {
|
|
831
|
+
const { loadConfig: loadCfg } = await Promise.resolve().then(() => require("../config.js"));
|
|
832
|
+
const cfg = await loadCfg(cg.getProjectRoot());
|
|
833
|
+
if (cfg.enableDocs) {
|
|
834
|
+
const db = cg.getDatabase();
|
|
835
|
+
db.applyDocsSchema();
|
|
836
|
+
const rawDb = db.getRawDb();
|
|
837
|
+
const docFiles = rawDb.get("SELECT COUNT(DISTINCT file_path) as cnt FROM doc_sections")?.cnt ?? 0;
|
|
838
|
+
const docSections = rawDb.get("SELECT COUNT(*) as cnt FROM doc_sections")?.cnt ?? 0;
|
|
839
|
+
const docRefs = rawDb.get("SELECT COUNT(*) as cnt FROM doc_code_refs")?.cnt ?? 0;
|
|
840
|
+
docsLine = ` Documentation: enabled \u2014 ${docFiles} files, ${docSections} sections, ${docRefs} code refs`;
|
|
841
|
+
}
|
|
842
|
+
} catch {
|
|
843
|
+
}
|
|
588
844
|
const threshold = stats.syncWarningThreshold ?? 10;
|
|
589
845
|
const pendingFiles = stats.pendingFiles ?? 0;
|
|
590
846
|
const syncRunning = stats.syncRunning ?? false;
|
|
@@ -613,6 +869,7 @@ class ToolHandler {
|
|
|
613
869
|
langLine ? ` By language: ${langLine}` : "",
|
|
614
870
|
frameworkLine,
|
|
615
871
|
archLine,
|
|
872
|
+
docsLine,
|
|
616
873
|
` DB size: ${dbMb} MB`,
|
|
617
874
|
...semanticLines,
|
|
618
875
|
...syncLines,
|
|
@@ -934,6 +1191,222 @@ class ToolHandler {
|
|
|
934
1191
|
}
|
|
935
1192
|
return lines.join("\n");
|
|
936
1193
|
}
|
|
1194
|
+
// ── Memory tools ────────────────────────────────────────────────────────
|
|
1195
|
+
case "kirograph_mem_search": {
|
|
1196
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1197
|
+
const projectRoot = cg.getProjectRoot();
|
|
1198
|
+
const config = await loadConfig(projectRoot);
|
|
1199
|
+
if (!config.enableMemory) return "Memory is not enabled. Set enableMemory: true in .kirograph/config.json";
|
|
1200
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
1201
|
+
const db = cg.getDatabase();
|
|
1202
|
+
db.applyMemorySchema();
|
|
1203
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
1204
|
+
mem.initialize();
|
|
1205
|
+
const results = await mem.search(args.query, {
|
|
1206
|
+
limit: args.limit ?? 10,
|
|
1207
|
+
kind: args.kind,
|
|
1208
|
+
sessionId: args.sessionId
|
|
1209
|
+
});
|
|
1210
|
+
if (results.length === 0) return `No memory observations found for "${args.query}".`;
|
|
1211
|
+
return results.map((r, i) => {
|
|
1212
|
+
const age = formatAge(r.observation.createdAt);
|
|
1213
|
+
return `${i + 1}. [${r.observation.kind}] ${r.observation.content} (${age})`;
|
|
1214
|
+
}).join("\n");
|
|
1215
|
+
}
|
|
1216
|
+
case "kirograph_mem_store": {
|
|
1217
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1218
|
+
const projectRoot = cg.getProjectRoot();
|
|
1219
|
+
const config = await loadConfig(projectRoot);
|
|
1220
|
+
if (!config.enableMemory) return "Memory is not enabled. Set enableMemory: true in .kirograph/config.json";
|
|
1221
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
1222
|
+
const db = cg.getDatabase();
|
|
1223
|
+
db.applyMemorySchema();
|
|
1224
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
1225
|
+
mem.initialize();
|
|
1226
|
+
const id = await mem.store({
|
|
1227
|
+
content: args.content,
|
|
1228
|
+
kind: args.kind ?? "note",
|
|
1229
|
+
source: "agent"
|
|
1230
|
+
});
|
|
1231
|
+
if (!id) return "Observation already exists (duplicate content).";
|
|
1232
|
+
return `Stored observation ${id} [${args.kind ?? "note"}]`;
|
|
1233
|
+
}
|
|
1234
|
+
case "kirograph_mem_timeline": {
|
|
1235
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1236
|
+
const projectRoot = cg.getProjectRoot();
|
|
1237
|
+
const config = await loadConfig(projectRoot);
|
|
1238
|
+
if (!config.enableMemory) return "Memory is not enabled. Set enableMemory: true in .kirograph/config.json";
|
|
1239
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
1240
|
+
const db = cg.getDatabase();
|
|
1241
|
+
db.applyMemorySchema();
|
|
1242
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
1243
|
+
mem.initialize();
|
|
1244
|
+
const { sessions, observations } = mem.timeline({
|
|
1245
|
+
limit: args.limit ?? 5,
|
|
1246
|
+
sessionId: args.sessionId
|
|
1247
|
+
});
|
|
1248
|
+
if (sessions.length === 0) return "No memory sessions found.";
|
|
1249
|
+
const lines = [];
|
|
1250
|
+
for (const session of sessions) {
|
|
1251
|
+
const start = new Date(session.startedAt).toISOString().slice(0, 16).replace("T", " ");
|
|
1252
|
+
const status = session.endedAt ? "ended" : "active";
|
|
1253
|
+
const obs = observations.get(session.id) ?? [];
|
|
1254
|
+
lines.push(`## ${start} [${session.ide ?? "unknown"}] (${status}, ${obs.length} observations)`);
|
|
1255
|
+
for (const o of obs.slice(0, 5)) {
|
|
1256
|
+
lines.push(` - [${o.kind}] ${o.content.slice(0, 120)}`);
|
|
1257
|
+
}
|
|
1258
|
+
if (obs.length > 5) lines.push(` \u2026and ${obs.length - 5} more`);
|
|
1259
|
+
}
|
|
1260
|
+
return lines.join("\n");
|
|
1261
|
+
}
|
|
1262
|
+
case "kirograph_mem_status": {
|
|
1263
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1264
|
+
const projectRoot = cg.getProjectRoot();
|
|
1265
|
+
const config = await loadConfig(projectRoot);
|
|
1266
|
+
if (!config.enableMemory) return "Memory is not enabled. Set enableMemory: true in .kirograph/config.json";
|
|
1267
|
+
const { MemoryManager } = await Promise.resolve().then(() => require("../memory/index.js"));
|
|
1268
|
+
const db = cg.getDatabase();
|
|
1269
|
+
db.applyMemorySchema();
|
|
1270
|
+
const mem = new MemoryManager(config, db.getRawDb());
|
|
1271
|
+
mem.initialize();
|
|
1272
|
+
const stats = mem.getStats();
|
|
1273
|
+
const lines = [
|
|
1274
|
+
"KiroGraph Memory Status",
|
|
1275
|
+
` Sessions: ${stats.sessions} (${stats.activeSessions} active)`,
|
|
1276
|
+
` Observations: ${stats.observations}`,
|
|
1277
|
+
` Symbol links: ${stats.links}`,
|
|
1278
|
+
` Embeddings: ${stats.vectors} / ${stats.embeddableCount}`,
|
|
1279
|
+
` Model mismatch: ${stats.modelMismatch ? "\u26A0 yes \u2014 run kirograph mem reembed" : "no"}`,
|
|
1280
|
+
` Caveman compression: ${config.cavemanMode !== "off" ? config.cavemanMode : "off (storing raw)"}`
|
|
1281
|
+
];
|
|
1282
|
+
return lines.join("\n");
|
|
1283
|
+
}
|
|
1284
|
+
// ── Docs tools ────────────────────────────────────────────────────────────
|
|
1285
|
+
case "kirograph_docs_toc": {
|
|
1286
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1287
|
+
const projectRoot = cg.getProjectRoot();
|
|
1288
|
+
const config = await loadConfig(projectRoot);
|
|
1289
|
+
if (!config.enableDocs) return "Documentation indexing is not enabled. Set enableDocs: true in .kirograph/config.json and run kirograph index.";
|
|
1290
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
1291
|
+
const db = cg.getDatabase();
|
|
1292
|
+
db.applyDocsSchema();
|
|
1293
|
+
const docs = new DocsQueries(db.getRawDb(), projectRoot);
|
|
1294
|
+
const toc = docs.getToc({ file: args.file, tree: args.tree });
|
|
1295
|
+
if (toc.length === 0) return args.file ? `No sections found in "${args.file}".` : "No documentation indexed. Run kirograph index.";
|
|
1296
|
+
const lines = [];
|
|
1297
|
+
const renderEntry = (entry, indent) => {
|
|
1298
|
+
const prefix = "#".repeat(entry.level || 1);
|
|
1299
|
+
const summary = entry.summary ? ` \u2014 ${entry.summary}` : "";
|
|
1300
|
+
lines.push(`${indent}${prefix} ${entry.title}${summary}`);
|
|
1301
|
+
lines.push(`${indent} ID: ${entry.id}`);
|
|
1302
|
+
if (entry.children?.length) {
|
|
1303
|
+
for (const child of entry.children) renderEntry(child, indent + " ");
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
if (args.tree) {
|
|
1307
|
+
for (const entry of toc) renderEntry(entry, "");
|
|
1308
|
+
} else {
|
|
1309
|
+
for (const entry of toc) {
|
|
1310
|
+
const prefix = "#".repeat(entry.level || 1);
|
|
1311
|
+
const summary = entry.summary ? ` \u2014 ${entry.summary}` : "";
|
|
1312
|
+
lines.push(`${prefix} ${entry.title} [${entry.filePath}]${summary}`);
|
|
1313
|
+
lines.push(` ID: ${entry.id}`);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return lines.join("\n");
|
|
1317
|
+
}
|
|
1318
|
+
case "kirograph_docs_search": {
|
|
1319
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1320
|
+
const projectRoot = cg.getProjectRoot();
|
|
1321
|
+
const config = await loadConfig(projectRoot);
|
|
1322
|
+
if (!config.enableDocs) return "Documentation indexing is not enabled. Set enableDocs: true in .kirograph/config.json and run kirograph index.";
|
|
1323
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
1324
|
+
const db = cg.getDatabase();
|
|
1325
|
+
db.applyDocsSchema();
|
|
1326
|
+
const docs = new DocsQueries(db.getRawDb(), projectRoot, config);
|
|
1327
|
+
const results = await docs.searchSections(args.query, {
|
|
1328
|
+
file: args.file,
|
|
1329
|
+
limit: args.limit ?? 10
|
|
1330
|
+
});
|
|
1331
|
+
if (results.length === 0) return `No documentation sections found matching "${args.query}".`;
|
|
1332
|
+
return results.map((r, i) => {
|
|
1333
|
+
const summary = r.section.summary ? `
|
|
1334
|
+
${r.section.summary}` : "";
|
|
1335
|
+
return `${i + 1}. ${r.section.title} [${r.section.filePath}]${summary}
|
|
1336
|
+
ID: ${r.section.id}`;
|
|
1337
|
+
}).join("\n\n");
|
|
1338
|
+
}
|
|
1339
|
+
case "kirograph_docs_section": {
|
|
1340
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1341
|
+
const projectRoot = cg.getProjectRoot();
|
|
1342
|
+
const config = await loadConfig(projectRoot);
|
|
1343
|
+
if (!config.enableDocs) return "Documentation indexing is not enabled. Set enableDocs: true in .kirograph/config.json and run kirograph index.";
|
|
1344
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
1345
|
+
const db = cg.getDatabase();
|
|
1346
|
+
db.applyDocsSchema();
|
|
1347
|
+
const docs = new DocsQueries(db.getRawDb(), projectRoot);
|
|
1348
|
+
const result = docs.getSection(args.id, { context: args.context });
|
|
1349
|
+
if (!result) return `Section "${args.id}" not found.`;
|
|
1350
|
+
const lines = [];
|
|
1351
|
+
if (result.ancestors?.length) {
|
|
1352
|
+
lines.push("Breadcrumb: " + result.ancestors.map((a) => a.title).join(" > ") + " > " + result.section.title);
|
|
1353
|
+
lines.push("");
|
|
1354
|
+
}
|
|
1355
|
+
lines.push(result.content);
|
|
1356
|
+
if (result.children?.length) {
|
|
1357
|
+
lines.push("", "## Child sections:");
|
|
1358
|
+
for (const child of result.children) {
|
|
1359
|
+
const summary = child.summary ? ` \u2014 ${child.summary}` : "";
|
|
1360
|
+
lines.push(` - ${child.title}${summary} (ID: ${child.id})`);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
return lines.join("\n");
|
|
1364
|
+
}
|
|
1365
|
+
case "kirograph_docs_outline": {
|
|
1366
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1367
|
+
const projectRoot = cg.getProjectRoot();
|
|
1368
|
+
const config = await loadConfig(projectRoot);
|
|
1369
|
+
if (!config.enableDocs) return "Documentation indexing is not enabled. Set enableDocs: true in .kirograph/config.json and run kirograph index.";
|
|
1370
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
1371
|
+
const db = cg.getDatabase();
|
|
1372
|
+
db.applyDocsSchema();
|
|
1373
|
+
const docs = new DocsQueries(db.getRawDb(), projectRoot);
|
|
1374
|
+
const outline = docs.getOutline(args.file);
|
|
1375
|
+
if (outline.length === 0) return `No sections found in "${args.file}". Is the file indexed?`;
|
|
1376
|
+
const lines = [`Outline: ${args.file}`, ""];
|
|
1377
|
+
const renderOutline = (entries, indent) => {
|
|
1378
|
+
for (const entry of entries) {
|
|
1379
|
+
const summary = entry.summary ? ` \u2014 ${entry.summary}` : "";
|
|
1380
|
+
lines.push(`${indent}${"#".repeat(entry.level || 1)} ${entry.title}${summary}`);
|
|
1381
|
+
if (entry.children?.length) renderOutline(entry.children, indent + " ");
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
renderOutline(outline, "");
|
|
1385
|
+
return lines.join("\n");
|
|
1386
|
+
}
|
|
1387
|
+
case "kirograph_docs_refs": {
|
|
1388
|
+
const { loadConfig } = await Promise.resolve().then(() => require("../config.js"));
|
|
1389
|
+
const projectRoot = cg.getProjectRoot();
|
|
1390
|
+
const config = await loadConfig(projectRoot);
|
|
1391
|
+
if (!config.enableDocs) return "Documentation indexing is not enabled. Set enableDocs: true in .kirograph/config.json and run kirograph index.";
|
|
1392
|
+
const { DocsQueries } = await Promise.resolve().then(() => require("../docs/queries.js"));
|
|
1393
|
+
const db = cg.getDatabase();
|
|
1394
|
+
db.applyDocsSchema();
|
|
1395
|
+
const docs = new DocsQueries(db.getRawDb(), projectRoot);
|
|
1396
|
+
const refs = docs.getRefs({
|
|
1397
|
+
sectionId: args.sectionId,
|
|
1398
|
+
qualifiedName: args.nodeId
|
|
1399
|
+
});
|
|
1400
|
+
if (refs.length === 0) {
|
|
1401
|
+
if (args.sectionId) return `No code references found in section "${args.sectionId}".`;
|
|
1402
|
+
if (args.nodeId) return `No documentation sections reference "${args.nodeId}".`;
|
|
1403
|
+
return "Provide either sectionId or nodeId to look up cross-references.";
|
|
1404
|
+
}
|
|
1405
|
+
return refs.map((r) => {
|
|
1406
|
+
const direction = args.sectionId ? `\u2192 ${r.qualifiedName}` : `\u2190 ${r.sectionTitle ?? r.sectionId}`;
|
|
1407
|
+
return `[${r.refType}] ${direction} (confidence: ${r.confidence.toFixed(2)})`;
|
|
1408
|
+
}).join("\n");
|
|
1409
|
+
}
|
|
937
1410
|
default:
|
|
938
1411
|
return `Unknown tool: ${toolName}`;
|
|
939
1412
|
}
|