mindgraph-mcp 0.24.0 → 0.26.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 +11 -2
- package/dist/cli.js +2027 -1808
- package/dist/index.js +1743 -1515
- package/dist/server.d.mts +19 -3
- package/dist/server.d.ts +19 -3
- package/dist/server.js +1734 -1611
- package/dist/server.mjs +1726 -1605
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -61,24 +61,24 @@ function resolvePendingCall(toolName, toolInput, options = {}) {
|
|
|
61
61
|
let matches = [];
|
|
62
62
|
for (const name of names) {
|
|
63
63
|
try {
|
|
64
|
-
const
|
|
64
|
+
const record2 = JSON.parse(
|
|
65
65
|
import_node_fs.default.readFileSync(import_node_path.default.join(dir, name), "utf8")
|
|
66
66
|
);
|
|
67
|
-
if (typeof
|
|
68
|
-
matches.push(
|
|
67
|
+
if (typeof record2.createdAt === "number" && now - record2.createdAt <= TTL_MS && record2.fills && typeof record2.fills === "object") {
|
|
68
|
+
matches.push(record2);
|
|
69
69
|
}
|
|
70
70
|
} catch {
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
if (matches.length > 1) {
|
|
74
74
|
const projectDir = options.projectDir ?? process.env.CLAUDE_PROJECT_DIR;
|
|
75
|
-
matches = projectDir ? matches.filter((
|
|
75
|
+
matches = projectDir ? matches.filter((record2) => record2.projectDir === projectDir) : [];
|
|
76
76
|
}
|
|
77
77
|
return matches.length === 1 ? matches[0].fills : void 0;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// src/index.ts
|
|
81
|
-
var import_stdio = require("@modelcontextprotocol/
|
|
81
|
+
var import_stdio = require("@modelcontextprotocol/server/stdio");
|
|
82
82
|
var import_mindgraph3 = require("mindgraph");
|
|
83
83
|
|
|
84
84
|
// src/hook-env.ts
|
|
@@ -116,9 +116,7 @@ function loadHookEnv(dir) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
// src/server.ts
|
|
119
|
-
var import_server = require("@modelcontextprotocol/
|
|
120
|
-
var import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
|
|
121
|
-
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
119
|
+
var import_server = require("@modelcontextprotocol/server");
|
|
122
120
|
|
|
123
121
|
// src/error-detail.ts
|
|
124
122
|
var import_mindgraph = require("mindgraph");
|
|
@@ -226,12 +224,21 @@ function unwrapSearchResult(value) {
|
|
|
226
224
|
}
|
|
227
225
|
return void 0;
|
|
228
226
|
}
|
|
227
|
+
function supersededBy(node) {
|
|
228
|
+
const marker = node.superseded;
|
|
229
|
+
if (!marker) return void 0;
|
|
230
|
+
const head = obj(marker);
|
|
231
|
+
if (!head) return str(node.superseded_by) ?? "";
|
|
232
|
+
const label = (str(head.head_label) ?? str(head.head_uid) ?? "").replace(/\s+/g, " ").trim();
|
|
233
|
+
const short = label.length <= 80 ? label : `${label.slice(0, 79)}\u2026`;
|
|
234
|
+
const date = str(head.head_stated_at);
|
|
235
|
+
return short && date ? `${short} (${date.slice(0, 10)})` : short;
|
|
236
|
+
}
|
|
229
237
|
function statusTag(node) {
|
|
230
238
|
const tags = [];
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
);
|
|
239
|
+
const replacement = supersededBy(node);
|
|
240
|
+
if (replacement !== void 0) {
|
|
241
|
+
tags.push(replacement ? `SUPERSEDED by ${replacement}` : "SUPERSEDED");
|
|
235
242
|
}
|
|
236
243
|
const truth = str(node.truth_status) ?? str(obj(node.props)?.truth_status);
|
|
237
244
|
if (truth && truth !== "accepted") tags.push(`truth: ${truth}`);
|
|
@@ -501,13 +508,13 @@ function resumeSection(heading, values, state, fallbackType) {
|
|
|
501
508
|
const items = values.map((value) => resumeEntry(value, state, fallbackType)).filter((value) => Boolean(value));
|
|
502
509
|
return items.length > 0 ? { heading, items } : void 0;
|
|
503
510
|
}
|
|
504
|
-
function renderResumeContext(response, maxChars) {
|
|
511
|
+
function renderResumeContext(response, maxChars, repositoryNames = {}) {
|
|
505
512
|
const payload = obj(response);
|
|
506
513
|
if (!payload) return void 0;
|
|
507
514
|
const state = { bounded: false, omitted: 0 };
|
|
508
515
|
const status = str(payload.status);
|
|
509
516
|
if (!payload.task && status === "no_eligible_work") {
|
|
510
|
-
const scopedOut =
|
|
517
|
+
const scopedOut = typeof payload.scoped_out_tasks === "number" ? payload.scoped_out_tasks : 0;
|
|
511
518
|
const note = scopedOut > 0 ? ` ${scopedOut} task(s) exist outside the requested scope.` : "";
|
|
512
519
|
return assemble(
|
|
513
520
|
"# Resume context",
|
|
@@ -521,6 +528,17 @@ function renderResumeContext(response, maxChars) {
|
|
|
521
528
|
if (section) sections.push(section);
|
|
522
529
|
};
|
|
523
530
|
push(resumeSection("## Current task", [payload.task], state, "Task"));
|
|
531
|
+
const other = otherEligibleWork(payload, repositoryNames);
|
|
532
|
+
if (other.shown > 0) {
|
|
533
|
+
sections.push({
|
|
534
|
+
heading: `## Other eligible work (${other.shown} shown${other.more > 0 ? `, ${other.more} more not listed` : ""})`,
|
|
535
|
+
items: other.groups.flatMap(
|
|
536
|
+
(group) => group.tasks.map(
|
|
537
|
+
(task) => `- ${group.repository}: ${task.label} [${task.uid}]${task.detail ? ` \u2014 ${task.detail}` : ""}`
|
|
538
|
+
)
|
|
539
|
+
)
|
|
540
|
+
});
|
|
541
|
+
}
|
|
524
542
|
push(
|
|
525
543
|
resumeSection(
|
|
526
544
|
"## Goal and project",
|
|
@@ -592,6 +610,37 @@ function renderResumeContext(response, maxChars) {
|
|
|
592
610
|
if (sections.length === 0) return void 0;
|
|
593
611
|
return assemble("# Resume context", sections, state, maxChars);
|
|
594
612
|
}
|
|
613
|
+
function otherEligibleWork(brief, names = {}) {
|
|
614
|
+
const listed = Array.isArray(brief?.other_eligible) ? brief.other_eligible : [];
|
|
615
|
+
const groups = [];
|
|
616
|
+
let shown = 0;
|
|
617
|
+
for (const entry of listed) {
|
|
618
|
+
const task = obj(entry);
|
|
619
|
+
const uid = typeof task?.uid === "string" ? task.uid : void 0;
|
|
620
|
+
if (!task || !uid) continue;
|
|
621
|
+
const scopes = Array.isArray(task.scope_uids) ? task.scope_uids.map(String) : [];
|
|
622
|
+
const named = scopes.find((scope) => names[scope]);
|
|
623
|
+
const repository = named ? names[named] : "Other scopes";
|
|
624
|
+
let group = groups.find((candidate) => candidate.repository === repository);
|
|
625
|
+
if (!group) {
|
|
626
|
+
group = { repository, tasks: [] };
|
|
627
|
+
groups.push(group);
|
|
628
|
+
}
|
|
629
|
+
const label = typeof task.label === "string" && task.label ? task.label : "(unlabeled)";
|
|
630
|
+
const detail = [
|
|
631
|
+
typeof task.status === "string" ? task.status : void 0,
|
|
632
|
+
typeof task.priority === "string" && task.priority ? `priority ${task.priority}` : void 0
|
|
633
|
+
].filter(Boolean).join(", ");
|
|
634
|
+
group.tasks.push({
|
|
635
|
+
uid,
|
|
636
|
+
label: label.length > 160 ? `${label.slice(0, 159)}\u2026` : label,
|
|
637
|
+
detail
|
|
638
|
+
});
|
|
639
|
+
shown += 1;
|
|
640
|
+
}
|
|
641
|
+
const total = typeof brief?.eligible_total === "number" ? brief.eligible_total : 0;
|
|
642
|
+
return { groups, shown, more: Math.max(0, total - 1 - shown) };
|
|
643
|
+
}
|
|
595
644
|
function renderNodeList(response, title, limit, maxChars) {
|
|
596
645
|
let candidates = [];
|
|
597
646
|
if (Array.isArray(response)) {
|
|
@@ -642,15 +691,15 @@ function renderTraversal(response, maxChars) {
|
|
|
642
691
|
const labelByUid = /* @__PURE__ */ new Map();
|
|
643
692
|
for (const node of nodes) labelByUid.set(str(node.uid), str(node.label) || "?");
|
|
644
693
|
if (paths.length > 0) {
|
|
645
|
-
const items = paths.map((raw) => obj(raw)).filter((
|
|
646
|
-
const uids = Array.isArray(
|
|
647
|
-
const labels = Array.isArray(
|
|
694
|
+
const items = paths.map((raw) => obj(raw)).filter((path7) => Boolean(path7)).map((path7, index) => {
|
|
695
|
+
const uids = Array.isArray(path7.node_uids) ? path7.node_uids.map(String) : [];
|
|
696
|
+
const labels = Array.isArray(path7.labels) ? path7.labels.map(String) : Array.isArray(path7.nodes) ? path7.nodes.map((hop) => {
|
|
648
697
|
const hopNode = obj(hop);
|
|
649
698
|
return str(hopNode?.label) || labelByUid.get(str(hopNode?.uid) || "") || str(hop) || "?";
|
|
650
699
|
}) : [];
|
|
651
700
|
const route = labels.length > 0 ? labels.join(" \u2192 ") : uids.join(" \u2192 ") || "(path)";
|
|
652
|
-
const cost = num(
|
|
653
|
-
const confidence = num(
|
|
701
|
+
const cost = num(path7.cost) ?? num(path7.path_cost);
|
|
702
|
+
const confidence = num(path7.path_confidence);
|
|
654
703
|
const meta = [
|
|
655
704
|
cost !== void 0 ? `cost ${cost}` : void 0,
|
|
656
705
|
confidence !== void 0 ? `confidence ${confidence}` : void 0
|
|
@@ -1652,777 +1701,168 @@ ${conversation}`
|
|
|
1652
1701
|
}
|
|
1653
1702
|
|
|
1654
1703
|
// src/memory-tool.ts
|
|
1704
|
+
var import_node_crypto4 = require("crypto");
|
|
1705
|
+
|
|
1706
|
+
// src/workspace-scope.ts
|
|
1707
|
+
var import_node_fs4 = __toESM(require("fs"));
|
|
1708
|
+
var import_node_path4 = __toESM(require("path"));
|
|
1709
|
+
|
|
1710
|
+
// src/codegraph.ts
|
|
1711
|
+
var import_node_child_process = require("child_process");
|
|
1712
|
+
var import_node_fs3 = require("fs");
|
|
1713
|
+
var import_promises = require("fs/promises");
|
|
1714
|
+
var import_node_os3 = require("os");
|
|
1715
|
+
var import_node_path3 = require("path");
|
|
1655
1716
|
var import_node_crypto3 = require("crypto");
|
|
1656
|
-
var
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
name: "mindgraph_memory",
|
|
1664
|
-
description: "Read the portable MindGraph memory surface. Use action='context' with mode='resume' or 'continuity' for authoritative task-first work state, and mode='topic' with a short keyword query for prior knowledge relevant to the user's request. Use action='status' to inspect integration capabilities and limitations. This tool never writes; durable capture and correction use the existing typed MindGraph write tools.",
|
|
1665
|
-
inputSchema: {
|
|
1666
|
-
type: "object",
|
|
1667
|
-
properties: {
|
|
1668
|
-
action: {
|
|
1669
|
-
type: "string",
|
|
1670
|
-
enum: ["status", "context"],
|
|
1671
|
-
description: "Read integration status or bounded memory context"
|
|
1672
|
-
},
|
|
1673
|
-
mode: {
|
|
1674
|
-
type: "string",
|
|
1675
|
-
enum: ["topic", "continuity", "resume"],
|
|
1676
|
-
description: "Context strategy. topic uses query-shaped retrieval; continuity/resume use authoritative task-first resume_work."
|
|
1677
|
-
},
|
|
1678
|
-
query: {
|
|
1679
|
-
type: "string",
|
|
1680
|
-
description: "Required for mode='topic': 1-3 discriminating BM25 keywords, not a full sentence"
|
|
1681
|
-
},
|
|
1682
|
-
project_uid: { type: "string", description: "Optional project scope" },
|
|
1683
|
-
task_uid: { type: "string", description: "Optional task scope for resume context" },
|
|
1684
|
-
session_uid: { type: "string", description: "Optional durable session scope" },
|
|
1685
|
-
scope_uids: {
|
|
1686
|
-
type: "array",
|
|
1687
|
-
items: { type: "string" },
|
|
1688
|
-
description: "Optional explicit graph scopes for continuity/resume"
|
|
1689
|
-
},
|
|
1690
|
-
node_types: {
|
|
1691
|
-
type: "array",
|
|
1692
|
-
items: { type: "string" },
|
|
1693
|
-
description: "Optional node-type filter for topic context"
|
|
1694
|
-
},
|
|
1695
|
-
layer: {
|
|
1696
|
-
type: "string",
|
|
1697
|
-
enum: ["reality", "epistemic", "intent", "action", "memory", "agent"],
|
|
1698
|
-
description: "Optional cognitive-layer filter for topic context"
|
|
1699
|
-
},
|
|
1700
|
-
limit: {
|
|
1701
|
-
type: "integer",
|
|
1702
|
-
minimum: 1,
|
|
1703
|
-
maximum: 50,
|
|
1704
|
-
default: 8,
|
|
1705
|
-
description: "Maximum direct graph items requested before bounded expansion"
|
|
1706
|
-
},
|
|
1707
|
-
include_chunks: {
|
|
1708
|
-
type: "boolean",
|
|
1709
|
-
default: false,
|
|
1710
|
-
description: "Include bounded source excerpts when topic summaries are insufficient"
|
|
1711
|
-
},
|
|
1712
|
-
include_documents: {
|
|
1713
|
-
type: "boolean",
|
|
1714
|
-
default: false,
|
|
1715
|
-
description: "Include bounded knowledge articles for topic context"
|
|
1716
|
-
},
|
|
1717
|
-
valid_at: {
|
|
1718
|
-
type: "string",
|
|
1719
|
-
description: "Optional ISO timestamp for time-aware topic retrieval"
|
|
1720
|
-
},
|
|
1721
|
-
graph_expansion_limit: {
|
|
1722
|
-
type: "integer",
|
|
1723
|
-
minimum: 0,
|
|
1724
|
-
maximum: 20,
|
|
1725
|
-
default: 3,
|
|
1726
|
-
description: "Bounded graph neighbors added after direct topic matches"
|
|
1727
|
-
},
|
|
1728
|
-
graph_max_depth: {
|
|
1729
|
-
type: "integer",
|
|
1730
|
-
minimum: 0,
|
|
1731
|
-
maximum: 5,
|
|
1732
|
-
default: 2,
|
|
1733
|
-
description: "Maximum graph-expansion depth for topic context"
|
|
1734
|
-
},
|
|
1735
|
-
max_output_chars: {
|
|
1736
|
-
type: "integer",
|
|
1737
|
-
minimum: MIN_OUTPUT_CHARS,
|
|
1738
|
-
maximum: MAX_OUTPUT_CHARS,
|
|
1739
|
-
default: DEFAULT_OUTPUT_CHARS,
|
|
1740
|
-
description: "Hard character budget for model-ready context; whole items are retained or omitted"
|
|
1741
|
-
},
|
|
1742
|
-
agent_id: { type: "string", description: "Agent identity" }
|
|
1743
|
-
},
|
|
1744
|
-
required: ["action"]
|
|
1745
|
-
},
|
|
1746
|
-
outputSchema: {
|
|
1747
|
-
type: "object",
|
|
1748
|
-
properties: {
|
|
1749
|
-
schema_version: { type: "string", const: RESULT_SCHEMA_VERSION },
|
|
1750
|
-
action: { type: "string", enum: ["status", "context"] },
|
|
1751
|
-
profile: { type: "string" },
|
|
1752
|
-
server: { type: "object" },
|
|
1753
|
-
integration: { type: "object" },
|
|
1754
|
-
capabilities: { type: "object" },
|
|
1755
|
-
degradation: { type: "array", items: { type: "object" } },
|
|
1756
|
-
context_id: { type: "string" },
|
|
1757
|
-
mode: { type: "string", enum: ["topic", "continuity", "resume"] },
|
|
1758
|
-
scope: { type: "object" },
|
|
1759
|
-
rendered_context: { type: "string" },
|
|
1760
|
-
rendered_hash: { type: "string" },
|
|
1761
|
-
items: { type: "array", items: { type: "object" } },
|
|
1762
|
-
retrieval_trace: { type: "object" },
|
|
1763
|
-
budget: { type: "object" },
|
|
1764
|
-
freshness: { type: "object" },
|
|
1765
|
-
warnings: { type: "array", items: { type: "object" } }
|
|
1766
|
-
},
|
|
1767
|
-
required: ["schema_version", "action"],
|
|
1768
|
-
oneOf: [
|
|
1769
|
-
{
|
|
1770
|
-
properties: { action: { const: "status" } },
|
|
1771
|
-
required: ["profile", "server", "integration", "scope", "capabilities", "degradation"]
|
|
1772
|
-
},
|
|
1773
|
-
{
|
|
1774
|
-
properties: { action: { const: "context" } },
|
|
1775
|
-
required: [
|
|
1776
|
-
"context_id",
|
|
1777
|
-
"mode",
|
|
1778
|
-
"scope",
|
|
1779
|
-
"rendered_context",
|
|
1780
|
-
"rendered_hash",
|
|
1781
|
-
"items",
|
|
1782
|
-
"retrieval_trace",
|
|
1783
|
-
"budget",
|
|
1784
|
-
"freshness",
|
|
1785
|
-
"warnings"
|
|
1786
|
-
]
|
|
1787
|
-
}
|
|
1788
|
-
]
|
|
1789
|
-
},
|
|
1790
|
-
annotations: {
|
|
1791
|
-
readOnlyHint: true,
|
|
1792
|
-
destructiveHint: false,
|
|
1793
|
-
idempotentHint: true,
|
|
1794
|
-
openWorldHint: false
|
|
1717
|
+
var UnknownRepositoryError = class extends Error {
|
|
1718
|
+
constructor(repo) {
|
|
1719
|
+
super(
|
|
1720
|
+
`unknown repository "${repo}": not declared in .mindgraph/workspace.json, not the current repository, and no such path exists`
|
|
1721
|
+
);
|
|
1722
|
+
this.repo = repo;
|
|
1723
|
+
this.name = "UnknownRepositoryError";
|
|
1795
1724
|
}
|
|
1725
|
+
repo;
|
|
1796
1726
|
};
|
|
1797
|
-
function
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1727
|
+
function invocationCwd(args) {
|
|
1728
|
+
const context = args.invocation_context;
|
|
1729
|
+
if (context && typeof context === "object" && !Array.isArray(context)) {
|
|
1730
|
+
const cwd = context.cwd;
|
|
1731
|
+
if (typeof cwd === "string" && cwd) return cwd;
|
|
1732
|
+
}
|
|
1733
|
+
return process.cwd();
|
|
1802
1734
|
}
|
|
1803
|
-
function
|
|
1804
|
-
|
|
1805
|
-
if (
|
|
1806
|
-
|
|
1735
|
+
function unavailabilityCaveats(reason, message) {
|
|
1736
|
+
const caveats = [message || "codegraph status failed"];
|
|
1737
|
+
if (reason === "absent") {
|
|
1738
|
+
caveats.push(
|
|
1739
|
+
"Optional: install codegraph (https://github.com/colbymchenry/codegraph) and run `codegraph init` in this repository to enable code anchoring and structural recall. Memory and work tools are unaffected."
|
|
1740
|
+
);
|
|
1807
1741
|
}
|
|
1808
|
-
return
|
|
1742
|
+
return caveats;
|
|
1809
1743
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1744
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
1745
|
+
var DEFAULT_STATUS_TTL_MS = 6e4;
|
|
1746
|
+
var MAX_OUTPUT_BYTES = 5 * 1024 * 1024;
|
|
1747
|
+
function normalizePath(path7) {
|
|
1748
|
+
return path7.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
1812
1749
|
}
|
|
1813
|
-
function
|
|
1814
|
-
|
|
1815
|
-
return Math.min(MAX_OUTPUT_CHARS, Math.max(MIN_OUTPUT_CHARS, Math.floor(value)));
|
|
1750
|
+
function normalizeSignature(signature) {
|
|
1751
|
+
return signature.replace(/\s+/g, " ").trim();
|
|
1816
1752
|
}
|
|
1817
|
-
function
|
|
1818
|
-
|
|
1753
|
+
function languageFromPath(path7) {
|
|
1754
|
+
const extension = (0, import_node_path3.extname)(path7).toLowerCase();
|
|
1755
|
+
return {
|
|
1756
|
+
".c": "c",
|
|
1757
|
+
".cc": "cpp",
|
|
1758
|
+
".cpp": "cpp",
|
|
1759
|
+
".go": "go",
|
|
1760
|
+
".java": "java",
|
|
1761
|
+
".js": "javascript",
|
|
1762
|
+
".jsx": "javascript",
|
|
1763
|
+
".kt": "kotlin",
|
|
1764
|
+
".py": "python",
|
|
1765
|
+
".rb": "ruby",
|
|
1766
|
+
".rs": "rust",
|
|
1767
|
+
".swift": "swift",
|
|
1768
|
+
".ts": "typescript",
|
|
1769
|
+
".tsx": "typescript"
|
|
1770
|
+
}[extension] ?? "unknown";
|
|
1819
1771
|
}
|
|
1820
|
-
function
|
|
1772
|
+
function asNode(hit) {
|
|
1773
|
+
return hit.node ?? hit;
|
|
1774
|
+
}
|
|
1775
|
+
function toCandidate(node) {
|
|
1776
|
+
if (!node.filePath || !node.kind || !(node.qualifiedName || node.name)) return null;
|
|
1821
1777
|
return {
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}),
|
|
1830
|
-
integration: {
|
|
1831
|
-
adapter_state: "model_controlled",
|
|
1832
|
-
harness: config.harness ?? "generic",
|
|
1833
|
-
configured_tool_profile: config.profile ?? "general",
|
|
1834
|
-
automatic_capture: false,
|
|
1835
|
-
automatic_delivery: false,
|
|
1836
|
-
delivery_verification: "unsupported",
|
|
1837
|
-
curator_mode: "disabled"
|
|
1838
|
-
},
|
|
1839
|
-
scope: defined({ org_id: config.orgId, agent_id: config.agentId }),
|
|
1840
|
-
capabilities: {
|
|
1841
|
-
status: true,
|
|
1842
|
-
topic_context: true,
|
|
1843
|
-
authoritative_resume_context: true,
|
|
1844
|
-
bounded_rendering: true,
|
|
1845
|
-
structured_content: true,
|
|
1846
|
-
typed_explicit_writes: true,
|
|
1847
|
-
lifecycle_event_ingest: false,
|
|
1848
|
-
automatic_context_injection: false,
|
|
1849
|
-
curator_mutation: false
|
|
1850
|
-
},
|
|
1851
|
-
degradation: [
|
|
1852
|
-
{
|
|
1853
|
-
code: "automatic_capture_unavailable",
|
|
1854
|
-
message: "M0 does not observe host lifecycle events; explicit typed write tools remain available."
|
|
1855
|
-
},
|
|
1856
|
-
{
|
|
1857
|
-
code: "delivery_unverified",
|
|
1858
|
-
message: "A successful MCP read does not prove that the host injected or used the returned context."
|
|
1859
|
-
},
|
|
1860
|
-
{
|
|
1861
|
-
code: "curator_disabled",
|
|
1862
|
-
message: "Curator proposals and autonomous mutation are not enabled in M0."
|
|
1863
|
-
}
|
|
1864
|
-
]
|
|
1778
|
+
path: normalizePath(node.filePath),
|
|
1779
|
+
language: node.language ?? languageFromPath(node.filePath),
|
|
1780
|
+
kind: node.kind,
|
|
1781
|
+
qualifiedName: node.qualifiedName ?? node.name ?? "",
|
|
1782
|
+
signature: node.signature ?? null,
|
|
1783
|
+
startLine: node.startLine ?? 1,
|
|
1784
|
+
endLine: node.endLine ?? node.startLine ?? 1
|
|
1865
1785
|
};
|
|
1866
1786
|
}
|
|
1867
|
-
function
|
|
1868
|
-
const
|
|
1869
|
-
if (
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
const wrapper = obj2(raw);
|
|
1874
|
-
if (!wrapper) return void 0;
|
|
1875
|
-
const value = obj2(wrapper.node) ?? obj2(wrapper.object) ?? wrapper;
|
|
1876
|
-
const uid = text(value.uid) ?? text(value.chunk_uid);
|
|
1877
|
-
if (!uid) return void 0;
|
|
1878
|
-
return defined({
|
|
1879
|
-
uid,
|
|
1880
|
-
type: fallbackType ?? nodeType(value),
|
|
1881
|
-
label: text(value.label) ?? text(value.document_title),
|
|
1882
|
-
truth_status: text(value.truth_status) ?? text(obj2(value.props)?.truth_status),
|
|
1883
|
-
superseded: value.superseded === true ? true : void 0,
|
|
1884
|
-
currently_valid: value.currently_valid === false ? false : void 0,
|
|
1885
|
-
valid_at_time: value.valid_at_time === false ? false : void 0,
|
|
1886
|
-
retrieval_origin: text(value.retrieval_origin),
|
|
1887
|
-
retrieval_depth: typeof value.retrieval_depth === "number" ? value.retrieval_depth : void 0
|
|
1888
|
-
});
|
|
1889
|
-
}
|
|
1890
|
-
function topicCandidates(raw) {
|
|
1891
|
-
const payload = obj2(raw);
|
|
1892
|
-
if (!payload) return [];
|
|
1893
|
-
const graph = obj2(payload.graph);
|
|
1894
|
-
const items = [];
|
|
1895
|
-
for (const article of Array.isArray(payload.articles) ? payload.articles : []) {
|
|
1896
|
-
const item = compactItem(article, "Article");
|
|
1897
|
-
if (item) items.push(item);
|
|
1898
|
-
}
|
|
1899
|
-
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
1900
|
-
const labels = /* @__PURE__ */ new Map();
|
|
1901
|
-
for (const node of rawNodes) {
|
|
1902
|
-
const item = compactItem(node);
|
|
1903
|
-
if (item) {
|
|
1904
|
-
if (HIDDEN_CONTEXT_NODE_TYPES.has(text(item.type) ?? "")) continue;
|
|
1905
|
-
items.push(item);
|
|
1906
|
-
const uid = text(item.uid);
|
|
1907
|
-
const label = text(item.label);
|
|
1908
|
-
if (uid && label) labels.set(uid, label);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
for (const rawEdge of Array.isArray(graph?.edges) ? graph.edges : []) {
|
|
1912
|
-
const edge = obj2(rawEdge);
|
|
1913
|
-
const fromUid = text(edge?.from_uid);
|
|
1914
|
-
const toUid = text(edge?.to_uid);
|
|
1915
|
-
const edgeType = text(edge?.edge_type) ?? text(obj2(edge?.edge_type)?.Custom);
|
|
1916
|
-
if (!fromUid || !toUid || !edgeType || HIDDEN_CONTEXT_EDGE_TYPES.has(edgeType) || !labels.has(fromUid) || !labels.has(toUid)) {
|
|
1917
|
-
continue;
|
|
1918
|
-
}
|
|
1919
|
-
items.push(
|
|
1920
|
-
defined({
|
|
1921
|
-
type: "Relationship",
|
|
1922
|
-
from_uid: fromUid,
|
|
1923
|
-
to_uid: toUid,
|
|
1924
|
-
edge_type: edgeType,
|
|
1925
|
-
from_label: labels.get(fromUid),
|
|
1926
|
-
to_label: labels.get(toUid)
|
|
1927
|
-
})
|
|
1928
|
-
);
|
|
1929
|
-
}
|
|
1930
|
-
for (const chunk of Array.isArray(payload.chunks) ? payload.chunks : []) {
|
|
1931
|
-
const item = compactItem(chunk, "SourceExcerpt");
|
|
1932
|
-
if (item) items.push(item);
|
|
1933
|
-
}
|
|
1934
|
-
return items;
|
|
1935
|
-
}
|
|
1936
|
-
function resumeCandidates(raw) {
|
|
1937
|
-
const payload = obj2(raw);
|
|
1938
|
-
if (!payload) return [];
|
|
1939
|
-
const items = [];
|
|
1940
|
-
for (const key of ["task", "goal", "project", "plan", "active_execution", "lease"]) {
|
|
1941
|
-
const item = compactItem(payload[key], key);
|
|
1942
|
-
if (item) items.push(item);
|
|
1943
|
-
}
|
|
1944
|
-
for (const key of ["next_steps", "recent_executions", "blockers", "code_targets"]) {
|
|
1945
|
-
for (const value of Array.isArray(payload[key]) ? payload[key] : []) {
|
|
1946
|
-
const item = compactItem(value, key.replace(/s$/, ""));
|
|
1947
|
-
if (item) items.push(item);
|
|
1948
|
-
}
|
|
1787
|
+
function normalizeRemote(remote) {
|
|
1788
|
+
const trimmed = remote.trim();
|
|
1789
|
+
if (!trimmed) return null;
|
|
1790
|
+
const scp = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(trimmed);
|
|
1791
|
+
if (scp && !trimmed.includes("://")) {
|
|
1792
|
+
return `${scp[1].toLowerCase()}/${scp[2].replace(/\.git$/, "")}`;
|
|
1949
1793
|
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1794
|
+
try {
|
|
1795
|
+
const url = new URL(trimmed);
|
|
1796
|
+
const pathname = url.pathname.replace(/\/$/, "").replace(/\.git$/, "");
|
|
1797
|
+
return `${url.host.toLowerCase()}${pathname}`;
|
|
1798
|
+
} catch {
|
|
1799
|
+
return null;
|
|
1956
1800
|
}
|
|
1957
|
-
return items;
|
|
1958
1801
|
}
|
|
1959
|
-
function
|
|
1960
|
-
const
|
|
1961
|
-
return
|
|
1962
|
-
const uid = text(item.uid);
|
|
1963
|
-
if (uid) {
|
|
1964
|
-
if (seen.has(uid) || !rendered2.includes(`[${uid}]`)) return false;
|
|
1965
|
-
seen.add(uid);
|
|
1966
|
-
return true;
|
|
1967
|
-
}
|
|
1968
|
-
if (item.type === "Relationship") {
|
|
1969
|
-
const from = text(item.from_label);
|
|
1970
|
-
const to = text(item.to_label);
|
|
1971
|
-
const edgeType = text(item.edge_type);
|
|
1972
|
-
if (!from || !to || !edgeType) return false;
|
|
1973
|
-
const key = `${text(item.from_uid)}:${edgeType}:${text(item.to_uid)}`;
|
|
1974
|
-
if (seen.has(key) || !rendered2.includes(`${from} \u2014${edgeType}\u2192 ${to}`)) return false;
|
|
1975
|
-
seen.add(key);
|
|
1976
|
-
return true;
|
|
1977
|
-
}
|
|
1978
|
-
return false;
|
|
1979
|
-
});
|
|
1802
|
+
function pathContains(root, candidate) {
|
|
1803
|
+
const child = (0, import_node_path3.relative)(root, candidate);
|
|
1804
|
+
return child === "" || child !== ".." && !child.startsWith(`..${import_node_path3.sep}`) && !(0, import_node_path3.isAbsolute)(child);
|
|
1980
1805
|
}
|
|
1981
|
-
function
|
|
1982
|
-
let
|
|
1983
|
-
|
|
1984
|
-
if (
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
const record = obj2(current);
|
|
1989
|
-
if (!record) return;
|
|
1990
|
-
for (const [key, item] of Object.entries(record)) {
|
|
1991
|
-
if (["updated_at", "created_at", "completed_at", "started_at", "observed_at"].includes(key) && typeof item === "string" && !Number.isNaN(Date.parse(item)) && (!latest || Date.parse(item) > Date.parse(latest))) {
|
|
1992
|
-
latest = item;
|
|
1806
|
+
function nearestExistingDirectory(candidate) {
|
|
1807
|
+
let current = (0, import_node_path3.resolve)(candidate);
|
|
1808
|
+
for (; ; ) {
|
|
1809
|
+
if ((0, import_node_fs3.existsSync)(current)) {
|
|
1810
|
+
try {
|
|
1811
|
+
return (0, import_node_fs3.statSync)(current).isDirectory() ? current : (0, import_node_path3.dirname)(current);
|
|
1812
|
+
} catch {
|
|
1993
1813
|
}
|
|
1994
|
-
visit(item);
|
|
1995
|
-
}
|
|
1996
|
-
};
|
|
1997
|
-
visit(value);
|
|
1998
|
-
return latest;
|
|
1999
|
-
}
|
|
2000
|
-
function contextWarnings(raw, rendered2, available, returned) {
|
|
2001
|
-
const warnings = [
|
|
2002
|
-
{
|
|
2003
|
-
code: "delivery_unverified",
|
|
2004
|
-
message: "The MCP server returned this context but cannot verify that the host injected or used it."
|
|
2005
|
-
}
|
|
2006
|
-
];
|
|
2007
|
-
const serialized = JSON.stringify(raw);
|
|
2008
|
-
if (available > returned || rendered2.includes("item(s) omitted")) {
|
|
2009
|
-
warnings.push({
|
|
2010
|
-
code: "context_bounded",
|
|
2011
|
-
message: `${Math.max(0, available - returned)} structured item(s) were omitted from the rendered context.`
|
|
2012
|
-
});
|
|
2013
|
-
}
|
|
2014
|
-
if (/"superseded":true/.test(serialized)) {
|
|
2015
|
-
warnings.push({ code: "superseded_items_present", message: "Some retrieved items are superseded." });
|
|
2016
|
-
}
|
|
2017
|
-
if (/"currently_valid":false|"valid_at_time":false/.test(serialized)) {
|
|
2018
|
-
warnings.push({
|
|
2019
|
-
code: "validity_warning",
|
|
2020
|
-
message: "Some retrieved items are outside their current or requested validity window."
|
|
2021
|
-
});
|
|
2022
|
-
}
|
|
2023
|
-
const payload = obj2(raw);
|
|
2024
|
-
if (payload?.truncated === true || obj2(payload?.truncation)) {
|
|
2025
|
-
const truncation = obj2(payload?.truncation);
|
|
2026
|
-
if (payload?.truncated === true || Object.values(truncation ?? {}).some(Boolean)) {
|
|
2027
|
-
warnings.push({ code: "source_truncated", message: "The authoritative source reported truncated fields." });
|
|
2028
1814
|
}
|
|
1815
|
+
const parent = (0, import_node_path3.dirname)(current);
|
|
1816
|
+
if (parent === current) return current;
|
|
1817
|
+
current = parent;
|
|
2029
1818
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
1819
|
+
}
|
|
1820
|
+
var MAX_CHILD_DIRECTORIES = 200;
|
|
1821
|
+
function findChildWorkspaceFiles(start) {
|
|
1822
|
+
let entries;
|
|
1823
|
+
try {
|
|
1824
|
+
entries = (0, import_node_fs3.readdirSync)(start, { withFileTypes: true });
|
|
1825
|
+
} catch {
|
|
1826
|
+
return [];
|
|
2032
1827
|
}
|
|
2033
|
-
return
|
|
1828
|
+
return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).slice(0, MAX_CHILD_DIRECTORIES).map((entry) => (0, import_node_path3.join)(start, entry.name, ".mindgraph", "workspace.json")).filter((candidate) => (0, import_node_fs3.existsSync)(candidate)).sort();
|
|
2034
1829
|
}
|
|
2035
|
-
function
|
|
2036
|
-
return
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
1830
|
+
function findWorkspaceFile(start, explicit) {
|
|
1831
|
+
if (explicit) return (0, import_node_path3.resolve)(start, explicit);
|
|
1832
|
+
let current = (0, import_node_path3.resolve)(start);
|
|
1833
|
+
for (; ; ) {
|
|
1834
|
+
const candidate = (0, import_node_path3.join)(current, ".mindgraph", "workspace.json");
|
|
1835
|
+
if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
|
|
1836
|
+
const parent = (0, import_node_path3.dirname)(current);
|
|
1837
|
+
if (parent === current) return void 0;
|
|
1838
|
+
current = parent;
|
|
1839
|
+
}
|
|
2040
1840
|
}
|
|
2041
|
-
async function
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
};
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.min(50, Math.max(1, Math.floor(args.limit))) : 8;
|
|
2067
|
-
const request = defined({
|
|
2068
|
-
query,
|
|
2069
|
-
project_uid: text(args.project_uid),
|
|
2070
|
-
node_limit: limit,
|
|
2071
|
-
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2072
|
-
layer: text(args.layer),
|
|
2073
|
-
chunk_limit: args.include_chunks === true ? limit : 0,
|
|
2074
|
-
article_limit: args.include_documents === true ? limit : 0,
|
|
2075
|
-
valid_at: text(args.valid_at),
|
|
2076
|
-
include_graph: true,
|
|
2077
|
-
graph_expansion_limit: typeof args.graph_expansion_limit === "number" ? args.graph_expansion_limit : 3,
|
|
2078
|
-
graph_max_depth: typeof args.graph_max_depth === "number" ? args.graph_max_depth : 2
|
|
2079
|
-
});
|
|
2080
|
-
raw = await client2.retrieveContext(request);
|
|
2081
|
-
rendered2 = renderContext(raw, budget) ?? "No results found for this search.";
|
|
2082
|
-
strategy = "retrieve_context";
|
|
2083
|
-
candidates = topicCandidates(raw);
|
|
2084
|
-
} else {
|
|
2085
|
-
const scopeUids = Array.from(
|
|
2086
|
-
/* @__PURE__ */ new Set([
|
|
2087
|
-
...Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : [],
|
|
2088
|
-
...text(args.project_uid) ? [text(args.project_uid)] : []
|
|
2089
|
-
])
|
|
2090
|
-
);
|
|
2091
|
-
raw = await client2.plan(
|
|
2092
|
-
defined({
|
|
2093
|
-
action: "resume_work",
|
|
2094
|
-
task_uid: text(args.task_uid),
|
|
2095
|
-
session_uid: text(args.session_uid),
|
|
2096
|
-
scope_uids: scopeUids.length > 0 ? scopeUids : void 0,
|
|
2097
|
-
limit: 1,
|
|
2098
|
-
agent_id: agentId
|
|
2099
|
-
})
|
|
2100
|
-
);
|
|
2101
|
-
rendered2 = renderResumeContext(raw, budget) ?? "No eligible work was found in the requested scope.";
|
|
2102
|
-
strategy = "resume_work";
|
|
2103
|
-
candidates = resumeCandidates(raw);
|
|
2104
|
-
}
|
|
2105
|
-
const items = visibleItems(candidates, rendered2);
|
|
2106
|
-
const renderedHash = sha256(rendered2);
|
|
2107
|
-
const scope = defined({
|
|
2108
|
-
org_id: config.orgId,
|
|
2109
|
-
agent_id: agentId,
|
|
2110
|
-
harness: config.harness ?? "generic",
|
|
2111
|
-
project_uid: text(args.project_uid),
|
|
2112
|
-
task_uid: text(args.task_uid),
|
|
2113
|
-
session_uid: text(args.session_uid),
|
|
2114
|
-
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0
|
|
2115
|
-
});
|
|
2116
|
-
const contextId = `ctx_${sha256(
|
|
2117
|
-
stableJson2({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
2118
|
-
).slice(0, 24)}`;
|
|
2119
|
-
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
2120
|
-
const result = {
|
|
2121
|
-
schema_version: RESULT_SCHEMA_VERSION,
|
|
2122
|
-
action: "context",
|
|
2123
|
-
context_id: contextId,
|
|
2124
|
-
mode,
|
|
2125
|
-
scope,
|
|
2126
|
-
rendered_context: rendered2,
|
|
2127
|
-
rendered_hash: renderedHash,
|
|
2128
|
-
items,
|
|
2129
|
-
retrieval_trace: defined({
|
|
2130
|
-
strategy,
|
|
2131
|
-
query: text(args.query),
|
|
2132
|
-
project_uid: text(args.project_uid),
|
|
2133
|
-
task_uid: text(args.task_uid),
|
|
2134
|
-
session_uid: text(args.session_uid),
|
|
2135
|
-
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2136
|
-
graph_expansion_limit: mode === "topic" ? args.graph_expansion_limit ?? 3 : void 0,
|
|
2137
|
-
graph_max_depth: mode === "topic" ? args.graph_max_depth ?? 2 : void 0,
|
|
2138
|
-
available_items: candidates.length,
|
|
2139
|
-
returned_items: items.length,
|
|
2140
|
-
omitted_items: Math.max(0, candidates.length - items.length)
|
|
2141
|
-
}),
|
|
2142
|
-
budget: {
|
|
2143
|
-
unit: "characters",
|
|
2144
|
-
requested_chars: budget,
|
|
2145
|
-
used_chars: rendered2.length,
|
|
2146
|
-
available_items: candidates.length,
|
|
2147
|
-
returned_items: items.length,
|
|
2148
|
-
omitted_items: Math.max(0, candidates.length - items.length),
|
|
2149
|
-
bounded
|
|
2150
|
-
},
|
|
2151
|
-
freshness: defined({
|
|
2152
|
-
valid_at: text(args.valid_at),
|
|
2153
|
-
latest_source_timestamp: latestTimestamp(raw)
|
|
2154
|
-
}),
|
|
2155
|
-
warnings: contextWarnings(raw, rendered2, candidates.length, items.length)
|
|
2156
|
-
};
|
|
2157
|
-
return {
|
|
2158
|
-
content: [{ type: "text", text: rendered2 }],
|
|
2159
|
-
structuredContent: result
|
|
2160
|
-
};
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
// src/resources.ts
|
|
2164
|
-
var RESOURCES = [
|
|
2165
|
-
{
|
|
2166
|
-
uri: "mindgraph://memory/status",
|
|
2167
|
-
name: "Memory Integration Status",
|
|
2168
|
-
description: "Portable memory profile, adapter state, supported capabilities, and explicit limitations",
|
|
2169
|
-
mimeType: "application/json"
|
|
2170
|
-
},
|
|
2171
|
-
{
|
|
2172
|
-
uri: "mindgraph://stats",
|
|
2173
|
-
name: "Graph Statistics",
|
|
2174
|
-
description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
|
|
2175
|
-
mimeType: "application/json"
|
|
2176
|
-
},
|
|
2177
|
-
{
|
|
2178
|
-
uri: "mindgraph://goals",
|
|
2179
|
-
name: "Active Goals",
|
|
2180
|
-
description: "All active goals in the knowledge graph",
|
|
2181
|
-
mimeType: "application/json"
|
|
2182
|
-
},
|
|
2183
|
-
{
|
|
2184
|
-
uri: "mindgraph://questions",
|
|
2185
|
-
name: "Open Questions",
|
|
2186
|
-
description: "All open questions in the knowledge graph",
|
|
2187
|
-
mimeType: "application/json"
|
|
2188
|
-
},
|
|
2189
|
-
{
|
|
2190
|
-
uri: "mindgraph://contradictions",
|
|
2191
|
-
name: "Contradictions",
|
|
2192
|
-
description: "Contradictory claims in the knowledge graph",
|
|
2193
|
-
mimeType: "application/json"
|
|
2194
|
-
},
|
|
2195
|
-
{
|
|
2196
|
-
uri: "mindgraph://decisions",
|
|
2197
|
-
name: "Open Decisions",
|
|
2198
|
-
description: "Unresolved decisions awaiting resolution",
|
|
2199
|
-
mimeType: "application/json"
|
|
2200
|
-
}
|
|
2201
|
-
];
|
|
2202
|
-
var RESOURCE_TEMPLATES = [
|
|
2203
|
-
{
|
|
2204
|
-
uriTemplate: "mindgraph://node/{uid}",
|
|
2205
|
-
name: "Graph Node",
|
|
2206
|
-
description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
|
|
2207
|
-
mimeType: "application/json"
|
|
2208
|
-
},
|
|
2209
|
-
{
|
|
2210
|
-
uriTemplate: "mindgraph://search/{query}",
|
|
2211
|
-
name: "Search Results",
|
|
2212
|
-
description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
|
|
2213
|
-
mimeType: "application/json"
|
|
2214
|
-
},
|
|
2215
|
-
{
|
|
2216
|
-
uriTemplate: "mindgraph://layer/{layer}",
|
|
2217
|
-
name: "Layer Nodes",
|
|
2218
|
-
description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
|
|
2219
|
-
mimeType: "application/json"
|
|
2220
|
-
}
|
|
2221
|
-
];
|
|
2222
|
-
var RESOURCE_GOVERNANCE_TOOL = "mindgraph_retrieve";
|
|
2223
|
-
function json(uri, data) {
|
|
2224
|
-
return {
|
|
2225
|
-
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
async function readResource(client2, uri, memoryConfig = {}) {
|
|
2229
|
-
switch (uri) {
|
|
2230
|
-
case "mindgraph://memory/status":
|
|
2231
|
-
return json(uri, memoryStatus(memoryConfig));
|
|
2232
|
-
case "mindgraph://stats":
|
|
2233
|
-
return json(uri, await client2.stats());
|
|
2234
|
-
case "mindgraph://goals":
|
|
2235
|
-
return json(uri, await client2.getGoals());
|
|
2236
|
-
case "mindgraph://questions":
|
|
2237
|
-
return json(uri, await client2.getOpenQuestions());
|
|
2238
|
-
case "mindgraph://contradictions":
|
|
2239
|
-
return json(uri, await client2.getContradictions());
|
|
2240
|
-
case "mindgraph://decisions":
|
|
2241
|
-
return json(uri, await client2.getOpenDecisions());
|
|
2242
|
-
}
|
|
2243
|
-
const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
|
|
2244
|
-
if (nodeMatch) {
|
|
2245
|
-
const uid = decodeURIComponent(nodeMatch[1]);
|
|
2246
|
-
const node = await client2.getNode(uid);
|
|
2247
|
-
const edges = await client2.getEdges({ from_uid: uid });
|
|
2248
|
-
const inEdges = await client2.getEdges({ to_uid: uid });
|
|
2249
|
-
return json(uri, { node, outgoing_edges: edges, incoming_edges: inEdges });
|
|
2250
|
-
}
|
|
2251
|
-
const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
|
|
2252
|
-
if (searchMatch) {
|
|
2253
|
-
const query = decodeURIComponent(searchMatch[1]);
|
|
2254
|
-
return json(uri, await client2.search(query, { limit: 20 }));
|
|
2255
|
-
}
|
|
2256
|
-
const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
|
|
2257
|
-
if (layerMatch) {
|
|
2258
|
-
const layer = decodeURIComponent(layerMatch[1]);
|
|
2259
|
-
return json(uri, await client2.getNodes({ layer, limit: 50 }));
|
|
2260
|
-
}
|
|
2261
|
-
throw new Error(`Unknown resource: ${uri}`);
|
|
2262
|
-
}
|
|
2263
|
-
async function readGovernedResource(client2, uri, governanceConfig, memoryConfig = {}) {
|
|
2264
|
-
const toolName = uri === "mindgraph://memory/status" ? "mindgraph_memory" : RESOURCE_GOVERNANCE_TOOL;
|
|
2265
|
-
const toolArgs = uri === "mindgraph://memory/status" ? { action: "status" } : {};
|
|
2266
|
-
const governance = await checkMcpGovernance(
|
|
2267
|
-
toolName,
|
|
2268
|
-
toolArgs,
|
|
2269
|
-
{ ...governanceConfig, context: { resource_uri: uri } }
|
|
2270
|
-
);
|
|
2271
|
-
if (!governance.allowed) {
|
|
2272
|
-
throw new Error(governance.message);
|
|
2273
|
-
}
|
|
2274
|
-
return readResource(client2, uri, memoryConfig);
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
// src/tools.ts
|
|
2278
|
-
var import_node_crypto6 = require("crypto");
|
|
2279
|
-
|
|
2280
|
-
// src/codegraph.ts
|
|
2281
|
-
var import_node_child_process = require("child_process");
|
|
2282
|
-
var import_node_fs3 = require("fs");
|
|
2283
|
-
var import_promises = require("fs/promises");
|
|
2284
|
-
var import_node_os3 = require("os");
|
|
2285
|
-
var import_node_path3 = require("path");
|
|
2286
|
-
var import_node_crypto4 = require("crypto");
|
|
2287
|
-
var UnknownRepositoryError = class extends Error {
|
|
2288
|
-
constructor(repo) {
|
|
2289
|
-
super(
|
|
2290
|
-
`unknown repository "${repo}": not declared in .mindgraph/workspace.json, not the current repository, and no such path exists`
|
|
2291
|
-
);
|
|
2292
|
-
this.repo = repo;
|
|
2293
|
-
this.name = "UnknownRepositoryError";
|
|
2294
|
-
}
|
|
2295
|
-
repo;
|
|
2296
|
-
};
|
|
2297
|
-
function invocationCwd(args) {
|
|
2298
|
-
const context = args.invocation_context;
|
|
2299
|
-
if (context && typeof context === "object" && !Array.isArray(context)) {
|
|
2300
|
-
const cwd = context.cwd;
|
|
2301
|
-
if (typeof cwd === "string" && cwd) return cwd;
|
|
2302
|
-
}
|
|
2303
|
-
return process.cwd();
|
|
2304
|
-
}
|
|
2305
|
-
function unavailabilityCaveats(reason, message) {
|
|
2306
|
-
const caveats = [message || "codegraph status failed"];
|
|
2307
|
-
if (reason === "absent") {
|
|
2308
|
-
caveats.push(
|
|
2309
|
-
"Optional: install codegraph (https://github.com/colbymchenry/codegraph) and run `codegraph init` in this repository to enable code anchoring and structural recall. Memory and work tools are unaffected."
|
|
2310
|
-
);
|
|
2311
|
-
}
|
|
2312
|
-
return caveats;
|
|
2313
|
-
}
|
|
2314
|
-
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
2315
|
-
var DEFAULT_STATUS_TTL_MS = 6e4;
|
|
2316
|
-
var MAX_OUTPUT_BYTES = 5 * 1024 * 1024;
|
|
2317
|
-
function normalizePath(path6) {
|
|
2318
|
-
return path6.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
2319
|
-
}
|
|
2320
|
-
function normalizeSignature(signature) {
|
|
2321
|
-
return signature.replace(/\s+/g, " ").trim();
|
|
2322
|
-
}
|
|
2323
|
-
function languageFromPath(path6) {
|
|
2324
|
-
const extension = (0, import_node_path3.extname)(path6).toLowerCase();
|
|
2325
|
-
return {
|
|
2326
|
-
".c": "c",
|
|
2327
|
-
".cc": "cpp",
|
|
2328
|
-
".cpp": "cpp",
|
|
2329
|
-
".go": "go",
|
|
2330
|
-
".java": "java",
|
|
2331
|
-
".js": "javascript",
|
|
2332
|
-
".jsx": "javascript",
|
|
2333
|
-
".kt": "kotlin",
|
|
2334
|
-
".py": "python",
|
|
2335
|
-
".rb": "ruby",
|
|
2336
|
-
".rs": "rust",
|
|
2337
|
-
".swift": "swift",
|
|
2338
|
-
".ts": "typescript",
|
|
2339
|
-
".tsx": "typescript"
|
|
2340
|
-
}[extension] ?? "unknown";
|
|
2341
|
-
}
|
|
2342
|
-
function asNode(hit) {
|
|
2343
|
-
return hit.node ?? hit;
|
|
2344
|
-
}
|
|
2345
|
-
function toCandidate(node) {
|
|
2346
|
-
if (!node.filePath || !node.kind || !(node.qualifiedName || node.name)) return null;
|
|
2347
|
-
return {
|
|
2348
|
-
path: normalizePath(node.filePath),
|
|
2349
|
-
language: node.language ?? languageFromPath(node.filePath),
|
|
2350
|
-
kind: node.kind,
|
|
2351
|
-
qualifiedName: node.qualifiedName ?? node.name ?? "",
|
|
2352
|
-
signature: node.signature ?? null,
|
|
2353
|
-
startLine: node.startLine ?? 1,
|
|
2354
|
-
endLine: node.endLine ?? node.startLine ?? 1
|
|
2355
|
-
};
|
|
2356
|
-
}
|
|
2357
|
-
function normalizeRemote(remote) {
|
|
2358
|
-
const trimmed = remote.trim();
|
|
2359
|
-
if (!trimmed) return null;
|
|
2360
|
-
const scp = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(trimmed);
|
|
2361
|
-
if (scp && !trimmed.includes("://")) {
|
|
2362
|
-
return `${scp[1].toLowerCase()}/${scp[2].replace(/\.git$/, "")}`;
|
|
2363
|
-
}
|
|
2364
|
-
try {
|
|
2365
|
-
const url = new URL(trimmed);
|
|
2366
|
-
const pathname = url.pathname.replace(/\/$/, "").replace(/\.git$/, "");
|
|
2367
|
-
return `${url.host.toLowerCase()}${pathname}`;
|
|
2368
|
-
} catch {
|
|
2369
|
-
return null;
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
function pathContains(root, candidate) {
|
|
2373
|
-
const child = (0, import_node_path3.relative)(root, candidate);
|
|
2374
|
-
return child === "" || child !== ".." && !child.startsWith(`..${import_node_path3.sep}`) && !(0, import_node_path3.isAbsolute)(child);
|
|
2375
|
-
}
|
|
2376
|
-
function nearestExistingDirectory(candidate) {
|
|
2377
|
-
let current = (0, import_node_path3.resolve)(candidate);
|
|
2378
|
-
for (; ; ) {
|
|
2379
|
-
if ((0, import_node_fs3.existsSync)(current)) {
|
|
2380
|
-
try {
|
|
2381
|
-
return (0, import_node_fs3.statSync)(current).isDirectory() ? current : (0, import_node_path3.dirname)(current);
|
|
2382
|
-
} catch {
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2385
|
-
const parent = (0, import_node_path3.dirname)(current);
|
|
2386
|
-
if (parent === current) return current;
|
|
2387
|
-
current = parent;
|
|
2388
|
-
}
|
|
2389
|
-
}
|
|
2390
|
-
function findWorkspaceFile(start, explicit) {
|
|
2391
|
-
if (explicit) return (0, import_node_path3.resolve)(start, explicit);
|
|
2392
|
-
let current = (0, import_node_path3.resolve)(start);
|
|
2393
|
-
for (; ; ) {
|
|
2394
|
-
const candidate = (0, import_node_path3.join)(current, ".mindgraph", "workspace.json");
|
|
2395
|
-
if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
|
|
2396
|
-
const parent = (0, import_node_path3.dirname)(current);
|
|
2397
|
-
if (parent === current) return void 0;
|
|
2398
|
-
current = parent;
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
async function runProcess(executable, args, timeoutMs, env, cwd) {
|
|
2402
|
-
return await new Promise((resolvePromise, rejectPromise) => {
|
|
2403
|
-
const child = (0, import_node_child_process.spawn)(executable, args, {
|
|
2404
|
-
cwd,
|
|
2405
|
-
env,
|
|
2406
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
2407
|
-
windowsHide: true
|
|
2408
|
-
});
|
|
2409
|
-
const stdout = [];
|
|
2410
|
-
const stderr = [];
|
|
2411
|
-
let outputBytes = 0;
|
|
2412
|
-
let timedOut = false;
|
|
2413
|
-
const timer = setTimeout(() => {
|
|
2414
|
-
timedOut = true;
|
|
2415
|
-
child.kill("SIGTERM");
|
|
2416
|
-
setTimeout(() => child.kill("SIGKILL"), 250).unref();
|
|
2417
|
-
}, timeoutMs);
|
|
2418
|
-
timer.unref();
|
|
2419
|
-
const collect = (target) => (chunk) => {
|
|
2420
|
-
outputBytes += chunk.length;
|
|
2421
|
-
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
2422
|
-
child.kill("SIGTERM");
|
|
2423
|
-
return;
|
|
2424
|
-
}
|
|
2425
|
-
target.push(chunk);
|
|
1841
|
+
async function runProcess(executable, args, timeoutMs, env, cwd) {
|
|
1842
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
1843
|
+
const child = (0, import_node_child_process.spawn)(executable, args, {
|
|
1844
|
+
cwd,
|
|
1845
|
+
env,
|
|
1846
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1847
|
+
windowsHide: true
|
|
1848
|
+
});
|
|
1849
|
+
const stdout = [];
|
|
1850
|
+
const stderr = [];
|
|
1851
|
+
let outputBytes = 0;
|
|
1852
|
+
let timedOut = false;
|
|
1853
|
+
const timer = setTimeout(() => {
|
|
1854
|
+
timedOut = true;
|
|
1855
|
+
child.kill("SIGTERM");
|
|
1856
|
+
setTimeout(() => child.kill("SIGKILL"), 250).unref();
|
|
1857
|
+
}, timeoutMs);
|
|
1858
|
+
timer.unref();
|
|
1859
|
+
const collect = (target) => (chunk) => {
|
|
1860
|
+
outputBytes += chunk.length;
|
|
1861
|
+
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
1862
|
+
child.kill("SIGTERM");
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
target.push(chunk);
|
|
2426
1866
|
};
|
|
2427
1867
|
child.stdout.on("data", collect(stdout));
|
|
2428
1868
|
child.stderr.on("data", collect(stderr));
|
|
@@ -2463,6 +1903,7 @@ var CodegraphAdapter = class {
|
|
|
2463
1903
|
env;
|
|
2464
1904
|
cwd;
|
|
2465
1905
|
workspaceFile;
|
|
1906
|
+
childWorkspaceFiles;
|
|
2466
1907
|
now;
|
|
2467
1908
|
identityCache = /* @__PURE__ */ new Map();
|
|
2468
1909
|
statusCache = /* @__PURE__ */ new Map();
|
|
@@ -2475,6 +1916,7 @@ var CodegraphAdapter = class {
|
|
|
2475
1916
|
this.cwd,
|
|
2476
1917
|
options.workspaceFile ?? this.env.MINDGRAPH_WORKSPACE_FILE
|
|
2477
1918
|
);
|
|
1919
|
+
this.childWorkspaceFiles = !this.workspaceFile && options.childWorkspaces ? findChildWorkspaceFiles(this.cwd) : [];
|
|
2478
1920
|
this.now = options.now ?? Date.now;
|
|
2479
1921
|
}
|
|
2480
1922
|
async resolveRepository(repo, fallbackSpaceUid) {
|
|
@@ -2572,7 +2014,7 @@ var CodegraphAdapter = class {
|
|
|
2572
2014
|
} catch {
|
|
2573
2015
|
}
|
|
2574
2016
|
(0, import_node_fs3.mkdirSync)(identityDir, { recursive: true, mode: 448 });
|
|
2575
|
-
const generated = (0,
|
|
2017
|
+
const generated = (0, import_node_crypto3.randomUUID)();
|
|
2576
2018
|
try {
|
|
2577
2019
|
(0, import_node_fs3.writeFileSync)(identityFile, `${generated}
|
|
2578
2020
|
`, {
|
|
@@ -2796,770 +2238,1550 @@ var CodegraphAdapter = class {
|
|
|
2796
2238
|
truncated: refs.length > cap
|
|
2797
2239
|
};
|
|
2798
2240
|
}
|
|
2799
|
-
configuredRepositories() {
|
|
2800
|
-
const configured = [];
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2241
|
+
configuredRepositories() {
|
|
2242
|
+
const configured = [];
|
|
2243
|
+
const workspaceFiles = this.workspaceFile ? [this.workspaceFile] : this.childWorkspaceFiles;
|
|
2244
|
+
for (const workspaceFile of workspaceFiles) {
|
|
2245
|
+
if (!(0, import_node_fs3.existsSync)(workspaceFile)) continue;
|
|
2246
|
+
try {
|
|
2247
|
+
const parsed = JSON.parse(
|
|
2248
|
+
(0, import_node_fs3.readFileSync)(workspaceFile, "utf8")
|
|
2249
|
+
);
|
|
2250
|
+
if (parsed.v === 1 && Array.isArray(parsed.repositories)) {
|
|
2251
|
+
const configDirectory = (0, import_node_path3.dirname)(workspaceFile);
|
|
2252
|
+
const base = (0, import_node_path3.basename)(configDirectory) === ".mindgraph" ? (0, import_node_path3.dirname)(configDirectory) : configDirectory;
|
|
2253
|
+
for (const repository of parsed.repositories) {
|
|
2254
|
+
if (!repository || typeof repository.root !== "string") continue;
|
|
2255
|
+
configured.push({
|
|
2256
|
+
repoId: typeof repository.repo_id === "string" ? repository.repo_id : void 0,
|
|
2257
|
+
repoRoot: (0, import_node_path3.resolve)(base, repository.root),
|
|
2258
|
+
spaceUid: typeof repository.space_uid === "string" ? repository.space_uid : void 0
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
} catch {
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
const raw = this.env.MINDGRAPH_CODE_REPOS;
|
|
2266
|
+
if (raw) {
|
|
2267
|
+
try {
|
|
2268
|
+
const parsed = JSON.parse(raw);
|
|
2269
|
+
for (const [repoId, config] of Object.entries(parsed)) {
|
|
2270
|
+
configured.push({
|
|
2271
|
+
repoId,
|
|
2272
|
+
repoRoot: (0, import_node_path3.resolve)(
|
|
2273
|
+
this.cwd,
|
|
2274
|
+
typeof config === "string" ? config : config.root
|
|
2275
|
+
),
|
|
2276
|
+
spaceUid: typeof config === "string" ? void 0 : config.space_uid
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
} catch {
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
return [
|
|
2283
|
+
...new Map(
|
|
2284
|
+
configured.map((repository) => [repository.repoRoot, repository])
|
|
2285
|
+
).values()
|
|
2286
|
+
];
|
|
2287
|
+
}
|
|
2288
|
+
async resolveOne(ref, repository) {
|
|
2289
|
+
const search = ref.symbol || ref.path;
|
|
2290
|
+
if (!search || ref.line !== void 0 && (!Number.isInteger(ref.line) || ref.line < 1)) {
|
|
2291
|
+
return { ref, candidates: [], error: "invalid_ref" };
|
|
2292
|
+
}
|
|
2293
|
+
try {
|
|
2294
|
+
const args = ["query", "-p", repository.repoRoot, "-j", "-l", "50"];
|
|
2295
|
+
if (ref.kind) args.push("-k", ref.kind);
|
|
2296
|
+
args.push(search);
|
|
2297
|
+
const hits = await this.runJson(args);
|
|
2298
|
+
let candidates = hits.map(asNode).map(toCandidate).filter((item) => item !== null);
|
|
2299
|
+
if (ref.path) {
|
|
2300
|
+
const absolutePath = (0, import_node_path3.isAbsolute)(ref.path) ? await (0, import_promises.realpath)(ref.path).catch(() => ref.path) : void 0;
|
|
2301
|
+
const wanted = normalizePath(
|
|
2302
|
+
absolutePath ? (0, import_node_path3.relative)(repository.repoRoot, absolutePath) : ref.path
|
|
2303
|
+
);
|
|
2304
|
+
candidates = candidates.filter((candidate) => candidate.path === wanted);
|
|
2305
|
+
}
|
|
2306
|
+
if (ref.language) {
|
|
2307
|
+
candidates = candidates.filter(
|
|
2308
|
+
(candidate) => candidate.language.toLowerCase() === ref.language?.toLowerCase()
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
if (ref.kind) {
|
|
2312
|
+
candidates = candidates.filter(
|
|
2313
|
+
(candidate) => candidate.kind.toLowerCase() === ref.kind?.toLowerCase()
|
|
2314
|
+
);
|
|
2315
|
+
}
|
|
2316
|
+
if (ref.symbol) {
|
|
2317
|
+
const exact = candidates.filter((candidate) => {
|
|
2318
|
+
const tail = candidate.qualifiedName.split(/::|\.|#/).at(-1);
|
|
2319
|
+
return candidate.qualifiedName === ref.symbol || tail === ref.symbol;
|
|
2320
|
+
});
|
|
2321
|
+
if (exact.length > 0) candidates = exact;
|
|
2322
|
+
}
|
|
2323
|
+
if (ref.signature) {
|
|
2324
|
+
const signature = normalizeSignature(ref.signature);
|
|
2325
|
+
candidates = candidates.filter(
|
|
2326
|
+
(candidate) => candidate.signature !== null && normalizeSignature(candidate.signature) === signature
|
|
2327
|
+
);
|
|
2328
|
+
}
|
|
2329
|
+
if (ref.line !== void 0) {
|
|
2330
|
+
candidates = candidates.filter(
|
|
2331
|
+
(candidate) => candidate.startLine <= ref.line && candidate.endLine >= ref.line
|
|
2332
|
+
);
|
|
2333
|
+
if (candidates.length > 1) {
|
|
2334
|
+
const narrowest = Math.min(
|
|
2335
|
+
...candidates.map((candidate) => candidate.endLine - candidate.startLine)
|
|
2336
|
+
);
|
|
2337
|
+
const narrowed = candidates.filter(
|
|
2338
|
+
(candidate) => candidate.endLine - candidate.startLine === narrowest
|
|
2339
|
+
);
|
|
2340
|
+
if (narrowed.length === 1) candidates = narrowed;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
if (candidates.length !== 1) {
|
|
2344
|
+
return {
|
|
2345
|
+
ref,
|
|
2346
|
+
candidates,
|
|
2347
|
+
error: candidates.length === 0 ? "not_found" : "ambiguous"
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
return {
|
|
2351
|
+
ref,
|
|
2352
|
+
candidates,
|
|
2353
|
+
resolved: {
|
|
2354
|
+
repoId: repository.repoId,
|
|
2355
|
+
repoRoot: repository.repoRoot,
|
|
2356
|
+
...candidates[0]
|
|
2357
|
+
}
|
|
2358
|
+
};
|
|
2359
|
+
} catch (cause) {
|
|
2360
|
+
const failure = cause;
|
|
2361
|
+
return {
|
|
2362
|
+
ref,
|
|
2363
|
+
candidates: [],
|
|
2364
|
+
error: failure.kind ?? "command_failed"
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
async related(action, resolved, limit) {
|
|
2369
|
+
const raw = await this.runJson([
|
|
2370
|
+
action,
|
|
2371
|
+
"-p",
|
|
2372
|
+
resolved.repoRoot,
|
|
2373
|
+
"-j",
|
|
2374
|
+
"-l",
|
|
2375
|
+
String(limit),
|
|
2376
|
+
resolved.qualifiedName
|
|
2377
|
+
]);
|
|
2378
|
+
const refs = (raw[action] ?? []).map((node) => ({
|
|
2379
|
+
path: node.filePath,
|
|
2380
|
+
line: node.startLine,
|
|
2381
|
+
symbol: node.qualifiedName ?? node.name,
|
|
2382
|
+
kind: node.kind
|
|
2383
|
+
}));
|
|
2384
|
+
return this.resolveRelatedRefs(refs, {
|
|
2385
|
+
repoId: resolved.repoId,
|
|
2386
|
+
repoRoot: resolved.repoRoot
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
async resolveRelatedRefs(refs, repository) {
|
|
2390
|
+
const results = await Promise.all(refs.map((ref) => this.resolveOne(ref, repository)));
|
|
2391
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2392
|
+
return results.flatMap((result) => result.resolved ? [result.resolved] : []).filter((result) => {
|
|
2393
|
+
const key = `${result.path}:${result.qualifiedName}:${result.startLine}`;
|
|
2394
|
+
if (seen.has(key)) return false;
|
|
2395
|
+
seen.add(key);
|
|
2396
|
+
return true;
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
async runJson(args) {
|
|
2400
|
+
const candidates = [
|
|
2401
|
+
this.env.MINDGRAPH_CODEGRAPH_BIN,
|
|
2402
|
+
"codegraph",
|
|
2403
|
+
(0, import_node_path3.resolve)((0, import_node_os3.homedir)(), ".local", "bin", "codegraph")
|
|
2404
|
+
].filter((candidate, index, all) => {
|
|
2405
|
+
return Boolean(candidate) && all.indexOf(candidate) === index;
|
|
2406
|
+
});
|
|
2407
|
+
let lastFailure;
|
|
2408
|
+
for (const executable of candidates) {
|
|
2409
|
+
try {
|
|
2410
|
+
const stdout = await runProcess(
|
|
2411
|
+
executable,
|
|
2412
|
+
args,
|
|
2413
|
+
this.timeoutMs,
|
|
2414
|
+
this.env,
|
|
2415
|
+
this.cwd
|
|
2416
|
+
);
|
|
2417
|
+
return JSON.parse(stdout);
|
|
2418
|
+
} catch (cause) {
|
|
2419
|
+
const failure = cause;
|
|
2420
|
+
lastFailure = failure;
|
|
2421
|
+
if (failure.kind !== "absent") throw failure;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
throw lastFailure ?? Object.assign(new Error("codegraph executable not found"), {
|
|
2425
|
+
kind: "absent"
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
function repositoryIdentityKey(repository) {
|
|
2430
|
+
return { v: 1, kind: "repository", repo_id: repository.repoId };
|
|
2431
|
+
}
|
|
2432
|
+
function codeRefIdentityKey(ref) {
|
|
2433
|
+
if (ref.kind === "file") {
|
|
2434
|
+
return {
|
|
2435
|
+
v: 1,
|
|
2436
|
+
kind: "file",
|
|
2437
|
+
repo_id: ref.repoId,
|
|
2438
|
+
path: ref.path
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
return {
|
|
2442
|
+
v: 1,
|
|
2443
|
+
kind: "symbol",
|
|
2444
|
+
repo_id: ref.repoId,
|
|
2445
|
+
language: ref.language,
|
|
2446
|
+
symbol_kind: ref.kind,
|
|
2447
|
+
qualified_name: ref.qualifiedName,
|
|
2448
|
+
disambiguator: {
|
|
2449
|
+
signature: ref.signature ?? "",
|
|
2450
|
+
path: ref.path
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
// src/code-tool.ts
|
|
2456
|
+
var ok2 = (data) => ({
|
|
2457
|
+
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
2458
|
+
});
|
|
2459
|
+
var err3 = (code, message, details) => ({
|
|
2460
|
+
content: [
|
|
2461
|
+
{
|
|
2462
|
+
type: "text",
|
|
2463
|
+
text: JSON.stringify({ error: message, code, details })
|
|
2464
|
+
}
|
|
2465
|
+
],
|
|
2466
|
+
isError: true
|
|
2467
|
+
});
|
|
2468
|
+
var CODE_TOOL = {
|
|
2469
|
+
name: "mindgraph_code",
|
|
2470
|
+
description: "Resolve typed code references through the local codegraph index and join them to persistent MindGraph memory/work. anchor creates exact repository/code anchors; recall reads attached graph context; expand reads callers/callees; affected reads impact for a code ref or Task/Execution. Ambiguous refs return candidates without writing. Refs with a path route to the repository defining that file (nearest declared root in .mindgraph/workspace.json); bare symbols resolve against the current repository only \u2014 pass path or repo to target a sibling.",
|
|
2471
|
+
inputSchema: {
|
|
2472
|
+
type: "object",
|
|
2473
|
+
properties: {
|
|
2474
|
+
action: {
|
|
2475
|
+
type: "string",
|
|
2476
|
+
enum: ["anchor", "recall", "expand", "affected"]
|
|
2477
|
+
},
|
|
2478
|
+
code_refs: {
|
|
2479
|
+
type: "array",
|
|
2480
|
+
maxItems: 50,
|
|
2481
|
+
items: {
|
|
2482
|
+
oneOf: [
|
|
2483
|
+
{ type: "string" },
|
|
2484
|
+
{
|
|
2485
|
+
type: "object",
|
|
2486
|
+
properties: {
|
|
2487
|
+
repo: { type: "string" },
|
|
2488
|
+
path: { type: "string" },
|
|
2489
|
+
line: { type: "integer", minimum: 1 },
|
|
2490
|
+
symbol: { type: "string" },
|
|
2491
|
+
kind: { type: "string" },
|
|
2492
|
+
language: { type: "string" },
|
|
2493
|
+
signature: { type: "string" }
|
|
2494
|
+
},
|
|
2495
|
+
additionalProperties: false
|
|
2496
|
+
}
|
|
2497
|
+
]
|
|
2498
|
+
}
|
|
2499
|
+
},
|
|
2500
|
+
anchor_uids: {
|
|
2501
|
+
type: "array",
|
|
2502
|
+
maxItems: 50,
|
|
2503
|
+
items: { type: "string" },
|
|
2504
|
+
description: "Already-materialized code anchor UIDs (codegraph is not required for recall)"
|
|
2505
|
+
},
|
|
2506
|
+
repo: {
|
|
2507
|
+
type: "string",
|
|
2508
|
+
description: "Configured repository id or repository root"
|
|
2509
|
+
},
|
|
2510
|
+
repo_space_uid: {
|
|
2511
|
+
type: "string",
|
|
2512
|
+
description: "Writable shared Project/repository Space for new anchors (anchor requires this, a workspace space_uid, or MINDGRAPH_CODE_SPACE_UID)"
|
|
2513
|
+
},
|
|
2514
|
+
task_uid: { type: "string" },
|
|
2515
|
+
execution_uid: { type: "string" },
|
|
2516
|
+
limit: { type: "integer", minimum: 1, maximum: 50 },
|
|
2517
|
+
agent_id: { type: "string" }
|
|
2518
|
+
},
|
|
2519
|
+
required: ["action"]
|
|
2520
|
+
},
|
|
2521
|
+
annotations: {
|
|
2522
|
+
readOnlyHint: false,
|
|
2523
|
+
destructiveHint: false,
|
|
2524
|
+
idempotentHint: true,
|
|
2525
|
+
openWorldHint: true
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
async function handleCodeTool(client2, args, adapter = new CodegraphAdapter({ cwd: invocationCwd(args) })) {
|
|
2529
|
+
const codeClient = client2;
|
|
2530
|
+
const action = args.action;
|
|
2531
|
+
const refs = Array.isArray(args.code_refs) ? args.code_refs : [];
|
|
2532
|
+
const anchorUids = Array.isArray(args.anchor_uids) ? args.anchor_uids : [];
|
|
2533
|
+
const agentId = typeof args.agent_id === "string" ? args.agent_id : "mcp";
|
|
2534
|
+
const fallbackSpaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : void 0;
|
|
2535
|
+
const options = {
|
|
2536
|
+
repo: typeof args.repo === "string" ? args.repo : void 0,
|
|
2537
|
+
fallbackSpaceUid
|
|
2538
|
+
};
|
|
2539
|
+
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
2540
|
+
try {
|
|
2541
|
+
switch (action) {
|
|
2542
|
+
case "anchor": {
|
|
2543
|
+
if (refs.length === 0) return err3("missing_code_refs", "code_refs is required for anchor");
|
|
2544
|
+
const resolution = await adapter.resolveRefs(refs, options);
|
|
2545
|
+
const resolved = resolution.results.flatMap(
|
|
2546
|
+
(result) => result.resolved && result.repository ? [{ ref: result.resolved, repository: result.repository }] : []
|
|
2805
2547
|
);
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
for (const repository of parsed.repositories) {
|
|
2810
|
-
if (!repository || typeof repository.root !== "string") continue;
|
|
2811
|
-
configured.push({
|
|
2812
|
-
repoId: typeof repository.repo_id === "string" ? repository.repo_id : void 0,
|
|
2813
|
-
repoRoot: (0, import_node_path3.resolve)(base, repository.root),
|
|
2814
|
-
spaceUid: typeof repository.space_uid === "string" ? repository.space_uid : void 0
|
|
2815
|
-
});
|
|
2816
|
-
}
|
|
2548
|
+
const unresolved = resolution.results.filter((result) => !result.resolved);
|
|
2549
|
+
if (resolved.length === 0) {
|
|
2550
|
+
return ok2({ ...resolution, anchors: [], wrote: false });
|
|
2817
2551
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2552
|
+
const missingSpace = resolved.find(
|
|
2553
|
+
({ repository }) => typeof args.repo_space_uid !== "string" && !repository.spaceUid
|
|
2554
|
+
);
|
|
2555
|
+
if (missingSpace) {
|
|
2556
|
+
return err3(
|
|
2557
|
+
"missing_repository_space",
|
|
2558
|
+
`repo_space_uid, a workspace space_uid, or MINDGRAPH_CODE_SPACE_UID is required for ${missingSpace.repository.repoId}`
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
const repositoryAnchors = /* @__PURE__ */ new Map();
|
|
2562
|
+
for (const { repository } of resolved) {
|
|
2563
|
+
if (repositoryAnchors.has(repository.repoRoot)) continue;
|
|
2564
|
+
const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
|
|
2565
|
+
const anchored = await anchorRepository(
|
|
2566
|
+
codeClient,
|
|
2567
|
+
repository,
|
|
2568
|
+
spaceUid,
|
|
2569
|
+
agentId
|
|
2570
|
+
);
|
|
2571
|
+
repositoryAnchors.set(repository.repoRoot, {
|
|
2572
|
+
...anchored,
|
|
2573
|
+
repository
|
|
2833
2574
|
});
|
|
2834
2575
|
}
|
|
2835
|
-
|
|
2576
|
+
const anchors = [];
|
|
2577
|
+
for (const { ref, repository } of resolved) {
|
|
2578
|
+
const repositoryAnchor = repositoryAnchors.get(repository.repoRoot);
|
|
2579
|
+
if (!repositoryAnchor.uid) continue;
|
|
2580
|
+
const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
|
|
2581
|
+
const anchor = await anchorCodeRef(
|
|
2582
|
+
codeClient,
|
|
2583
|
+
ref,
|
|
2584
|
+
repositoryAnchor.uid,
|
|
2585
|
+
spaceUid,
|
|
2586
|
+
agentId
|
|
2587
|
+
);
|
|
2588
|
+
anchors.push(anchor);
|
|
2589
|
+
}
|
|
2590
|
+
return ok2({
|
|
2591
|
+
availability: resolution.availability,
|
|
2592
|
+
repository: repositoryAnchors.values().next().value,
|
|
2593
|
+
repositories: [...repositoryAnchors.values()],
|
|
2594
|
+
anchors,
|
|
2595
|
+
unresolved,
|
|
2596
|
+
wrote: anchors.some((anchor) => anchor.created)
|
|
2597
|
+
});
|
|
2836
2598
|
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
const
|
|
2857
|
-
|
|
2858
|
-
|
|
2599
|
+
case "recall": {
|
|
2600
|
+
const materialized = new Set(anchorUids);
|
|
2601
|
+
let resolution;
|
|
2602
|
+
if (refs.length > 0) {
|
|
2603
|
+
resolution = await adapter.resolveRefs(refs, options);
|
|
2604
|
+
for (const result of resolution.results) {
|
|
2605
|
+
if (!result.resolved) continue;
|
|
2606
|
+
const uid = await resolveMaterializedUid(codeClient, result.resolved, agentId);
|
|
2607
|
+
if (uid) materialized.add(uid);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
if (materialized.size === 0) {
|
|
2611
|
+
return ok2({
|
|
2612
|
+
availability: resolution?.availability,
|
|
2613
|
+
anchors: [],
|
|
2614
|
+
context: [],
|
|
2615
|
+
unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
|
|
2616
|
+
});
|
|
2617
|
+
}
|
|
2618
|
+
const context = await Promise.all(
|
|
2619
|
+
[...materialized].map(async (uid) => ({
|
|
2620
|
+
anchor_uid: uid,
|
|
2621
|
+
graph: await codeClient.traverse({
|
|
2622
|
+
action: "neighborhood",
|
|
2623
|
+
start_uid: uid,
|
|
2624
|
+
depth: 2,
|
|
2625
|
+
max_nodes: Math.min(limit ?? 20, 20)
|
|
2626
|
+
})
|
|
2627
|
+
}))
|
|
2859
2628
|
);
|
|
2860
|
-
|
|
2629
|
+
return ok2({
|
|
2630
|
+
availability: resolution?.availability,
|
|
2631
|
+
anchors: [...materialized],
|
|
2632
|
+
context,
|
|
2633
|
+
unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
|
|
2634
|
+
});
|
|
2861
2635
|
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2636
|
+
case "expand": {
|
|
2637
|
+
const target = await resolveSingleTarget(
|
|
2638
|
+
codeClient,
|
|
2639
|
+
adapter,
|
|
2640
|
+
refs,
|
|
2641
|
+
anchorUids,
|
|
2642
|
+
options
|
|
2643
|
+
);
|
|
2644
|
+
if ("error" in target) return target.error;
|
|
2645
|
+
const expanded = await adapter.expand(target.ref, limit);
|
|
2646
|
+
const joined = await joinMaterialized(
|
|
2647
|
+
codeClient,
|
|
2648
|
+
[...expanded.callers, ...expanded.callees],
|
|
2649
|
+
agentId,
|
|
2650
|
+
Math.min(limit ?? 20, 20)
|
|
2865
2651
|
);
|
|
2652
|
+
return ok2({ anchor: target.ref, ...expanded, materialized: joined });
|
|
2866
2653
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2654
|
+
case "affected": {
|
|
2655
|
+
const targetUid = typeof args.task_uid === "string" ? args.task_uid : typeof args.execution_uid === "string" ? args.execution_uid : void 0;
|
|
2656
|
+
let graphContext;
|
|
2657
|
+
const graphRefs = [];
|
|
2658
|
+
let unavailableRepositories = [];
|
|
2659
|
+
if (targetUid) {
|
|
2660
|
+
graphContext = await codeClient.traverse({
|
|
2661
|
+
action: "neighborhood",
|
|
2662
|
+
start_uid: targetUid,
|
|
2663
|
+
depth: 2,
|
|
2664
|
+
max_nodes: 50
|
|
2665
|
+
});
|
|
2666
|
+
const fromGraph = await codeRefsFromGraphContext(
|
|
2667
|
+
codeClient,
|
|
2668
|
+
adapter,
|
|
2669
|
+
graphContext
|
|
2670
|
+
);
|
|
2671
|
+
graphRefs.push(...fromGraph.refs);
|
|
2672
|
+
unavailableRepositories = fromGraph.unavailable;
|
|
2673
|
+
}
|
|
2674
|
+
if (refs.length > 0 || anchorUids.length > 0) {
|
|
2675
|
+
const target = await resolveSingleTarget(
|
|
2676
|
+
codeClient,
|
|
2677
|
+
adapter,
|
|
2678
|
+
refs,
|
|
2679
|
+
anchorUids,
|
|
2680
|
+
options
|
|
2681
|
+
);
|
|
2682
|
+
if ("error" in target) return target.error;
|
|
2683
|
+
graphRefs.unshift(target.ref);
|
|
2684
|
+
}
|
|
2685
|
+
const unique = uniqueRefs(graphRefs);
|
|
2686
|
+
if (unique.length === 0) {
|
|
2687
|
+
return ok2({
|
|
2688
|
+
target_uid: targetUid,
|
|
2689
|
+
graph_context: graphContext,
|
|
2690
|
+
affected: [],
|
|
2691
|
+
degradation: unavailableRepositories.length > 0 ? `attached code anchors reference repositories unavailable here: ${unavailableRepositories.join(", ")}` : "no materialized code anchors were attached",
|
|
2692
|
+
...unavailableRepositories.length > 0 ? { unavailable_repositories: unavailableRepositories } : {}
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
const impacts = await Promise.all(
|
|
2696
|
+
unique.map(async (ref) => ({ anchor: ref, ...await adapter.affected(ref, limit) }))
|
|
2697
|
+
);
|
|
2698
|
+
const structural = uniqueRefs(impacts.flatMap((impact) => impact.affected));
|
|
2699
|
+
const joined = await joinMaterialized(
|
|
2700
|
+
codeClient,
|
|
2701
|
+
structural,
|
|
2702
|
+
agentId,
|
|
2703
|
+
Math.min(limit ?? 50, 50)
|
|
2870
2704
|
);
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2705
|
+
return ok2({
|
|
2706
|
+
target_uid: targetUid,
|
|
2707
|
+
graph_context: graphContext,
|
|
2708
|
+
impacts,
|
|
2709
|
+
materialized: joined,
|
|
2710
|
+
...unavailableRepositories.length > 0 ? { unavailable_repositories: unavailableRepositories } : {}
|
|
2876
2711
|
});
|
|
2877
|
-
if (exact.length > 0) candidates = exact;
|
|
2878
2712
|
}
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2713
|
+
default:
|
|
2714
|
+
return err3("unknown_action", `unknown mindgraph_code action: ${action}`);
|
|
2715
|
+
}
|
|
2716
|
+
} catch (cause) {
|
|
2717
|
+
if (cause instanceof UnknownRepositoryError) {
|
|
2718
|
+
return err3("unknown_repository", cause.message);
|
|
2719
|
+
}
|
|
2720
|
+
return toolError(cause, "code_tool_failed");
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
async function attachCodeRefsToToolResult(client2, result, args, adapter) {
|
|
2724
|
+
if (result.isError || !Array.isArray(args.code_refs) || args.code_refs.length === 0) {
|
|
2725
|
+
return result;
|
|
2726
|
+
}
|
|
2727
|
+
const original = JSON.parse(result.content[0]?.text ?? "null");
|
|
2728
|
+
const targetUids = primaryUids(original);
|
|
2729
|
+
if (targetUids.length === 0) {
|
|
2730
|
+
return ok2({
|
|
2731
|
+
result: original,
|
|
2732
|
+
code_anchors: {
|
|
2733
|
+
wrote: false,
|
|
2734
|
+
caveat: "the write response exposed no primary UID to attach"
|
|
2884
2735
|
}
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
const anchorResult = await handleCodeTool(
|
|
2739
|
+
client2,
|
|
2740
|
+
{
|
|
2741
|
+
action: "anchor",
|
|
2742
|
+
code_refs: args.code_refs,
|
|
2743
|
+
repo: args.repo,
|
|
2744
|
+
repo_space_uid: args.repo_space_uid,
|
|
2745
|
+
agent_id: args.agent_id,
|
|
2746
|
+
// Keeps the default adapter anchored to the live session directory
|
|
2747
|
+
// rather than wherever the MCP server process was launched.
|
|
2748
|
+
invocation_context: args.invocation_context
|
|
2749
|
+
},
|
|
2750
|
+
adapter
|
|
2751
|
+
);
|
|
2752
|
+
const anchors = JSON.parse(anchorResult.content[0]?.text ?? "null");
|
|
2753
|
+
if (!anchorResult.isError) {
|
|
2754
|
+
const codeClient = client2;
|
|
2755
|
+
const anchorUids = (anchors.anchors ?? []).flatMap(
|
|
2756
|
+
(anchor) => anchor.uid ? [anchor.uid] : []
|
|
2757
|
+
);
|
|
2758
|
+
const relateFailures = [];
|
|
2759
|
+
for (const targetUid of targetUids) {
|
|
2760
|
+
for (const anchorUid of anchorUids) {
|
|
2761
|
+
try {
|
|
2762
|
+
await codeClient.entity({
|
|
2763
|
+
action: "relate",
|
|
2764
|
+
source_uid: targetUid,
|
|
2765
|
+
target_uid: anchorUid,
|
|
2766
|
+
edge_type: args.action === "lesson" ? "ABOUT" : "RELEVANT_TO",
|
|
2767
|
+
agent_id: args.agent_id
|
|
2768
|
+
});
|
|
2769
|
+
} catch (cause) {
|
|
2770
|
+
relateFailures.push(
|
|
2771
|
+
`${targetUid} -> ${anchorUid}: ${errorDetail(cause)}`
|
|
2895
2772
|
);
|
|
2896
|
-
if (narrowed.length === 1) candidates = narrowed;
|
|
2897
2773
|
}
|
|
2898
2774
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
return {
|
|
2907
|
-
ref,
|
|
2908
|
-
candidates,
|
|
2909
|
-
resolved: {
|
|
2910
|
-
repoId: repository.repoId,
|
|
2911
|
-
repoRoot: repository.repoRoot,
|
|
2912
|
-
...candidates[0]
|
|
2775
|
+
}
|
|
2776
|
+
if (relateFailures.length > 0) {
|
|
2777
|
+
return ok2({
|
|
2778
|
+
result: original,
|
|
2779
|
+
code_anchors: {
|
|
2780
|
+
...anchors,
|
|
2781
|
+
caveat: `anchors written, but ${relateFailures.length} relate edge(s) failed: ${relateFailures.join("; ")}`
|
|
2913
2782
|
}
|
|
2914
|
-
};
|
|
2915
|
-
}
|
|
2916
|
-
|
|
2783
|
+
});
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
return ok2({ result: original, code_anchors: anchors });
|
|
2787
|
+
}
|
|
2788
|
+
async function anchorRepository(client2, repository, spaceUid, agentId) {
|
|
2789
|
+
return client2.entity({
|
|
2790
|
+
action: "create",
|
|
2791
|
+
label: repository.repoId,
|
|
2792
|
+
props: {
|
|
2793
|
+
entity_type: "repository",
|
|
2794
|
+
canonical_name: repository.repoId,
|
|
2795
|
+
identifiers: { repo_id: repository.repoId }
|
|
2796
|
+
},
|
|
2797
|
+
identity: {
|
|
2798
|
+
namespace: "external.code",
|
|
2799
|
+
key_version: 1,
|
|
2800
|
+
key: repositoryIdentityKey(repository)
|
|
2801
|
+
},
|
|
2802
|
+
identity_space_uid: spaceUid,
|
|
2803
|
+
agent_id: agentId
|
|
2804
|
+
});
|
|
2805
|
+
}
|
|
2806
|
+
async function anchorCodeRef(client2, ref, repositoryUid, spaceUid, agentId) {
|
|
2807
|
+
const response = await client2.entity({
|
|
2808
|
+
action: "create",
|
|
2809
|
+
label: ref.qualifiedName,
|
|
2810
|
+
props: {
|
|
2811
|
+
entity_type: ref.kind === "file" ? "code_file" : "code_symbol",
|
|
2812
|
+
canonical_name: ref.qualifiedName,
|
|
2813
|
+
identifiers: {
|
|
2814
|
+
repo_id: ref.repoId,
|
|
2815
|
+
path: ref.path,
|
|
2816
|
+
qualified_name: ref.qualifiedName
|
|
2817
|
+
},
|
|
2818
|
+
attributes: { code_ref: storedCodeRef(ref) }
|
|
2819
|
+
},
|
|
2820
|
+
identity: {
|
|
2821
|
+
namespace: "external.code",
|
|
2822
|
+
key_version: 1,
|
|
2823
|
+
key: codeRefIdentityKey(ref)
|
|
2824
|
+
},
|
|
2825
|
+
identity_space_uid: spaceUid,
|
|
2826
|
+
agent_id: agentId
|
|
2827
|
+
});
|
|
2828
|
+
if (response.uid && response.created !== false && response.status !== "existing") {
|
|
2829
|
+
await client2.entity({
|
|
2830
|
+
action: "relate",
|
|
2831
|
+
source_uid: response.uid,
|
|
2832
|
+
target_uid: repositoryUid,
|
|
2833
|
+
edge_type: "PART_OF",
|
|
2834
|
+
agent_id: agentId
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2837
|
+
return { ...response, ref };
|
|
2838
|
+
}
|
|
2839
|
+
async function resolveMaterializedUid(client2, ref, agentId) {
|
|
2840
|
+
const response = await client2.entity({
|
|
2841
|
+
action: "resolve_identity",
|
|
2842
|
+
identity: {
|
|
2843
|
+
namespace: "external.code",
|
|
2844
|
+
key_version: 1,
|
|
2845
|
+
key: codeRefIdentityKey(ref)
|
|
2846
|
+
},
|
|
2847
|
+
agent_id: agentId
|
|
2848
|
+
});
|
|
2849
|
+
return response.status === "existing" ? response.uid : void 0;
|
|
2850
|
+
}
|
|
2851
|
+
async function codeRefFromAnchor(client2, adapter, uid) {
|
|
2852
|
+
const node = await client2.getNode(uid);
|
|
2853
|
+
const attributes = node.props?.attributes;
|
|
2854
|
+
if (!attributes || typeof attributes !== "object") return void 0;
|
|
2855
|
+
const codeRef = attributes.code_ref;
|
|
2856
|
+
if (!isStoredCodeRef(codeRef)) return void 0;
|
|
2857
|
+
try {
|
|
2858
|
+
const repository = await adapter.resolveRepository(codeRef.repoId);
|
|
2859
|
+
return { ref: { ...codeRef, repoRoot: repository.repoRoot } };
|
|
2860
|
+
} catch (cause) {
|
|
2861
|
+
if (cause instanceof UnknownRepositoryError) {
|
|
2862
|
+
return { missingRepo: codeRef.repoId };
|
|
2863
|
+
}
|
|
2864
|
+
throw cause;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
async function resolveSingleTarget(client2, adapter, refs, anchorUids, options) {
|
|
2868
|
+
if (refs.length > 1 || anchorUids.length > 1) {
|
|
2869
|
+
return { error: err3("ambiguous_target", "expand/affected accepts exactly one code target") };
|
|
2870
|
+
}
|
|
2871
|
+
if (anchorUids.length === 1) {
|
|
2872
|
+
const outcome = await codeRefFromAnchor(client2, adapter, anchorUids[0]);
|
|
2873
|
+
if (!outcome) {
|
|
2874
|
+
return { error: err3("invalid_anchor", "anchor UID does not contain a typed code_ref") };
|
|
2875
|
+
}
|
|
2876
|
+
if ("missingRepo" in outcome) {
|
|
2917
2877
|
return {
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2878
|
+
error: err3(
|
|
2879
|
+
"repository_unavailable",
|
|
2880
|
+
`repository ${outcome.missingRepo} is not checked out here or declared in .mindgraph/workspace.json; expand/affected need its local index`
|
|
2881
|
+
)
|
|
2921
2882
|
};
|
|
2922
2883
|
}
|
|
2884
|
+
return { ref: outcome.ref };
|
|
2923
2885
|
}
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
action,
|
|
2927
|
-
"-p",
|
|
2928
|
-
resolved.repoRoot,
|
|
2929
|
-
"-j",
|
|
2930
|
-
"-l",
|
|
2931
|
-
String(limit),
|
|
2932
|
-
resolved.qualifiedName
|
|
2933
|
-
]);
|
|
2934
|
-
const refs = (raw[action] ?? []).map((node) => ({
|
|
2935
|
-
path: node.filePath,
|
|
2936
|
-
line: node.startLine,
|
|
2937
|
-
symbol: node.qualifiedName ?? node.name,
|
|
2938
|
-
kind: node.kind
|
|
2939
|
-
}));
|
|
2940
|
-
return this.resolveRelatedRefs(refs, {
|
|
2941
|
-
repoId: resolved.repoId,
|
|
2942
|
-
repoRoot: resolved.repoRoot
|
|
2943
|
-
});
|
|
2886
|
+
if (refs.length !== 1) {
|
|
2887
|
+
return { error: err3("missing_code_ref", "one code_ref or anchor_uid is required") };
|
|
2944
2888
|
}
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
return
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2889
|
+
const resolution = await adapter.resolveRefs(refs, options);
|
|
2890
|
+
const result = resolution.results[0];
|
|
2891
|
+
if (!result.resolved) {
|
|
2892
|
+
return {
|
|
2893
|
+
error: ok2({
|
|
2894
|
+
availability: resolution.availability,
|
|
2895
|
+
result,
|
|
2896
|
+
wrote: false
|
|
2897
|
+
})
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
return { ref: result.resolved };
|
|
2901
|
+
}
|
|
2902
|
+
async function joinMaterialized(client2, refs, agentId, limit) {
|
|
2903
|
+
const joined = [];
|
|
2904
|
+
for (const ref of uniqueRefs(refs).slice(0, limit)) {
|
|
2905
|
+
const uid = await resolveMaterializedUid(client2, ref, agentId);
|
|
2906
|
+
if (!uid) continue;
|
|
2907
|
+
joined.push({
|
|
2908
|
+
ref,
|
|
2909
|
+
anchor_uid: uid,
|
|
2910
|
+
graph: await client2.traverse({
|
|
2911
|
+
action: "neighborhood",
|
|
2912
|
+
start_uid: uid,
|
|
2913
|
+
depth: 2,
|
|
2914
|
+
max_nodes: 20
|
|
2915
|
+
})
|
|
2953
2916
|
});
|
|
2954
2917
|
}
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2918
|
+
return joined;
|
|
2919
|
+
}
|
|
2920
|
+
async function codeRefsFromGraphContext(client2, adapter, context) {
|
|
2921
|
+
const uids = /* @__PURE__ */ new Set();
|
|
2922
|
+
collectUids(context, uids);
|
|
2923
|
+
if (uids.size === 0) return { refs: [], unavailable: [] };
|
|
2924
|
+
const nodes = client2.getNodesBatch ? await client2.getNodesBatch([...uids]) : await Promise.all([...uids].map((uid) => client2.getNode(uid).catch(() => void 0)));
|
|
2925
|
+
const stored = nodes.flatMap((node) => {
|
|
2926
|
+
if (!node) return [];
|
|
2927
|
+
const attributes = node.props?.attributes;
|
|
2928
|
+
if (!attributes || typeof attributes !== "object") return [];
|
|
2929
|
+
const codeRef = attributes.code_ref;
|
|
2930
|
+
return isStoredCodeRef(codeRef) ? [codeRef] : [];
|
|
2931
|
+
});
|
|
2932
|
+
const refs = [];
|
|
2933
|
+
const unavailable = /* @__PURE__ */ new Set();
|
|
2934
|
+
for (const ref of stored) {
|
|
2935
|
+
try {
|
|
2936
|
+
const repository = await adapter.resolveRepository(ref.repoId);
|
|
2937
|
+
refs.push({ ...ref, repoRoot: repository.repoRoot });
|
|
2938
|
+
} catch (cause) {
|
|
2939
|
+
if (cause instanceof UnknownRepositoryError) {
|
|
2940
|
+
unavailable.add(ref.repoId);
|
|
2941
|
+
} else {
|
|
2942
|
+
throw cause;
|
|
2978
2943
|
}
|
|
2979
2944
|
}
|
|
2980
|
-
throw lastFailure ?? Object.assign(new Error("codegraph executable not found"), {
|
|
2981
|
-
kind: "absent"
|
|
2982
|
-
});
|
|
2983
2945
|
}
|
|
2984
|
-
};
|
|
2985
|
-
function repositoryIdentityKey(repository) {
|
|
2986
|
-
return { v: 1, kind: "repository", repo_id: repository.repoId };
|
|
2946
|
+
return { refs, unavailable: [...unavailable].sort() };
|
|
2987
2947
|
}
|
|
2988
|
-
function
|
|
2989
|
-
if (
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
kind: "file",
|
|
2993
|
-
repo_id: ref.repoId,
|
|
2994
|
-
path: ref.path
|
|
2995
|
-
};
|
|
2948
|
+
function collectUids(value, uids) {
|
|
2949
|
+
if (Array.isArray(value)) {
|
|
2950
|
+
value.forEach((item) => collectUids(item, uids));
|
|
2951
|
+
return;
|
|
2996
2952
|
}
|
|
2997
|
-
return
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
qualified_name: ref.qualifiedName,
|
|
3004
|
-
disambiguator: {
|
|
3005
|
-
signature: ref.signature ?? "",
|
|
3006
|
-
path: ref.path
|
|
2953
|
+
if (!value || typeof value !== "object") return;
|
|
2954
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2955
|
+
if (typeof child === "string" && ["uid", "node_uid", "neighbor_uid", "from_uid", "to_uid"].includes(key)) {
|
|
2956
|
+
uids.add(child);
|
|
2957
|
+
} else {
|
|
2958
|
+
collectUids(child, uids);
|
|
3007
2959
|
}
|
|
3008
|
-
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
function isStoredCodeRef(value) {
|
|
2963
|
+
if (!value || typeof value !== "object") return false;
|
|
2964
|
+
const ref = value;
|
|
2965
|
+
return typeof ref.repoId === "string" && typeof ref.path === "string" && typeof ref.language === "string" && typeof ref.kind === "string" && typeof ref.qualifiedName === "string" && (typeof ref.signature === "string" || ref.signature === null) && typeof ref.startLine === "number" && typeof ref.endLine === "number";
|
|
2966
|
+
}
|
|
2967
|
+
function storedCodeRef(ref) {
|
|
2968
|
+
const { repoRoot: _localOnly, ...stored } = ref;
|
|
2969
|
+
return stored;
|
|
2970
|
+
}
|
|
2971
|
+
function uniqueRefs(refs) {
|
|
2972
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2973
|
+
return refs.filter((ref) => {
|
|
2974
|
+
const key = `${ref.repoId}:${ref.path}:${ref.qualifiedName}:${ref.signature ?? ""}`;
|
|
2975
|
+
if (seen.has(key)) return false;
|
|
2976
|
+
seen.add(key);
|
|
2977
|
+
return true;
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2980
|
+
function primaryUids(value) {
|
|
2981
|
+
if (!value || typeof value !== "object") return [];
|
|
2982
|
+
const object = value;
|
|
2983
|
+
const keys = [
|
|
2984
|
+
"uid",
|
|
2985
|
+
"claim_uid",
|
|
2986
|
+
"goal_uid",
|
|
2987
|
+
"project_uid",
|
|
2988
|
+
"milestone_uid",
|
|
2989
|
+
"decision_uid",
|
|
2990
|
+
"task_uid",
|
|
2991
|
+
"plan_uid",
|
|
2992
|
+
"step_uid",
|
|
2993
|
+
"execution_uid",
|
|
2994
|
+
"lesson_uid"
|
|
2995
|
+
];
|
|
2996
|
+
return [
|
|
2997
|
+
...new Set(
|
|
2998
|
+
keys.flatMap((key) => typeof object[key] === "string" ? [object[key]] : [])
|
|
2999
|
+
)
|
|
3000
|
+
];
|
|
3009
3001
|
}
|
|
3010
3002
|
|
|
3011
|
-
// src/
|
|
3012
|
-
var
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
action: {
|
|
3031
|
-
type: "string",
|
|
3032
|
-
enum: ["anchor", "recall", "expand", "affected"]
|
|
3033
|
-
},
|
|
3034
|
-
code_refs: {
|
|
3035
|
-
type: "array",
|
|
3036
|
-
maxItems: 50,
|
|
3037
|
-
items: {
|
|
3038
|
-
oneOf: [
|
|
3039
|
-
{ type: "string" },
|
|
3040
|
-
{
|
|
3041
|
-
type: "object",
|
|
3042
|
-
properties: {
|
|
3043
|
-
repo: { type: "string" },
|
|
3044
|
-
path: { type: "string" },
|
|
3045
|
-
line: { type: "integer", minimum: 1 },
|
|
3046
|
-
symbol: { type: "string" },
|
|
3047
|
-
kind: { type: "string" },
|
|
3048
|
-
language: { type: "string" },
|
|
3049
|
-
signature: { type: "string" }
|
|
3050
|
-
},
|
|
3051
|
-
additionalProperties: false
|
|
3052
|
-
}
|
|
3053
|
-
]
|
|
3054
|
-
}
|
|
3055
|
-
},
|
|
3056
|
-
anchor_uids: {
|
|
3057
|
-
type: "array",
|
|
3058
|
-
maxItems: 50,
|
|
3059
|
-
items: { type: "string" },
|
|
3060
|
-
description: "Already-materialized code anchor UIDs (codegraph is not required for recall)"
|
|
3061
|
-
},
|
|
3062
|
-
repo: {
|
|
3063
|
-
type: "string",
|
|
3064
|
-
description: "Configured repository id or repository root"
|
|
3065
|
-
},
|
|
3066
|
-
repo_space_uid: {
|
|
3067
|
-
type: "string",
|
|
3068
|
-
description: "Writable shared Project/repository Space for new anchors (anchor requires this, a workspace space_uid, or MINDGRAPH_CODE_SPACE_UID)"
|
|
3069
|
-
},
|
|
3070
|
-
task_uid: { type: "string" },
|
|
3071
|
-
execution_uid: { type: "string" },
|
|
3072
|
-
limit: { type: "integer", minimum: 1, maximum: 50 },
|
|
3073
|
-
agent_id: { type: "string" }
|
|
3074
|
-
},
|
|
3075
|
-
required: ["action"]
|
|
3076
|
-
},
|
|
3077
|
-
annotations: {
|
|
3078
|
-
readOnlyHint: false,
|
|
3079
|
-
destructiveHint: false,
|
|
3080
|
-
idempotentHint: true,
|
|
3081
|
-
openWorldHint: true
|
|
3003
|
+
// src/workspace-scope.ts
|
|
3004
|
+
var WORKSPACE_RESUME_LIMIT = 9;
|
|
3005
|
+
var SCOPE_CACHE_TTL_MS = 12 * 60 * 60 * 1e3;
|
|
3006
|
+
var SCOPE_CACHE_FILE = "repository-scopes.json";
|
|
3007
|
+
function readScopeCache(cache) {
|
|
3008
|
+
if (!cache) return {};
|
|
3009
|
+
try {
|
|
3010
|
+
const parsed = JSON.parse(
|
|
3011
|
+
import_node_fs4.default.readFileSync(import_node_path4.default.join(cache.dir, SCOPE_CACHE_FILE), "utf8")
|
|
3012
|
+
);
|
|
3013
|
+
if (parsed.v !== 1 || parsed.tenant !== cache.tenant || !parsed.entries) return {};
|
|
3014
|
+
const now = (cache.now ?? Date.now)();
|
|
3015
|
+
return Object.fromEntries(
|
|
3016
|
+
Object.entries(parsed.entries).filter(
|
|
3017
|
+
([, entry]) => typeof entry?.uid === "string" && typeof entry.at === "number" && now - entry.at >= 0 && now - entry.at < SCOPE_CACHE_TTL_MS
|
|
3018
|
+
)
|
|
3019
|
+
);
|
|
3020
|
+
} catch {
|
|
3021
|
+
return {};
|
|
3082
3022
|
}
|
|
3083
|
-
}
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
const action = args.action;
|
|
3087
|
-
const refs = Array.isArray(args.code_refs) ? args.code_refs : [];
|
|
3088
|
-
const anchorUids = Array.isArray(args.anchor_uids) ? args.anchor_uids : [];
|
|
3089
|
-
const agentId = typeof args.agent_id === "string" ? args.agent_id : "mcp";
|
|
3090
|
-
const fallbackSpaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : void 0;
|
|
3091
|
-
const options = {
|
|
3092
|
-
repo: typeof args.repo === "string" ? args.repo : void 0,
|
|
3093
|
-
fallbackSpaceUid
|
|
3094
|
-
};
|
|
3095
|
-
const limit = typeof args.limit === "number" ? args.limit : void 0;
|
|
3023
|
+
}
|
|
3024
|
+
function writeScopeCache(cache, entries) {
|
|
3025
|
+
if (!cache) return;
|
|
3096
3026
|
try {
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3027
|
+
import_node_fs4.default.mkdirSync(cache.dir, { recursive: true, mode: 448 });
|
|
3028
|
+
const file = import_node_path4.default.join(cache.dir, SCOPE_CACHE_FILE);
|
|
3029
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
3030
|
+
import_node_fs4.default.writeFileSync(
|
|
3031
|
+
temporary,
|
|
3032
|
+
JSON.stringify({ v: 1, tenant: cache.tenant, entries }),
|
|
3033
|
+
{ mode: 384 }
|
|
3034
|
+
);
|
|
3035
|
+
import_node_fs4.default.renameSync(temporary, file);
|
|
3036
|
+
} catch {
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
function record(value) {
|
|
3040
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3041
|
+
}
|
|
3042
|
+
async function resolveRepositoryScope(cwd, client2, agentId, options = {}) {
|
|
3043
|
+
if (!client2.entity) return { uids: [], names: {}, failures: [] };
|
|
3044
|
+
const adapter = new CodegraphAdapter({
|
|
3045
|
+
cwd,
|
|
3046
|
+
workspaceFile: options.workspaceFile,
|
|
3047
|
+
childWorkspaces: true
|
|
3048
|
+
});
|
|
3049
|
+
const configured = await adapter.resolveRepositories();
|
|
3050
|
+
const repositories = configured.length > 0 ? configured : [await adapter.resolveRepository()];
|
|
3051
|
+
const failures = [];
|
|
3052
|
+
const names = {};
|
|
3053
|
+
const cached = readScopeCache(options.cache);
|
|
3054
|
+
const fresh = {};
|
|
3055
|
+
const stamp = (options.cache?.now ?? Date.now)();
|
|
3056
|
+
const resolved = await Promise.all(
|
|
3057
|
+
repositories.map(async (repository) => {
|
|
3058
|
+
const remembered = cached[repository.repoId];
|
|
3059
|
+
if (remembered) {
|
|
3060
|
+
names[remembered.uid] = repository.repoId;
|
|
3061
|
+
return remembered.uid;
|
|
3062
|
+
}
|
|
3063
|
+
try {
|
|
3064
|
+
const payload = record(
|
|
3065
|
+
await client2.entity({
|
|
3066
|
+
action: "resolve_identity",
|
|
3067
|
+
identity: {
|
|
3068
|
+
namespace: "external.code",
|
|
3069
|
+
key_version: 1,
|
|
3070
|
+
key: repositoryIdentityKey(repository)
|
|
3071
|
+
},
|
|
3072
|
+
agent_id: agentId
|
|
3073
|
+
})
|
|
3110
3074
|
);
|
|
3111
|
-
if (
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
);
|
|
3075
|
+
if (payload?.status === "existing" && typeof payload.uid === "string" && payload.uid) {
|
|
3076
|
+
names[payload.uid] = repository.repoId;
|
|
3077
|
+
fresh[repository.repoId] = { uid: payload.uid, at: stamp };
|
|
3078
|
+
return payload.uid;
|
|
3116
3079
|
}
|
|
3117
|
-
|
|
3118
|
-
for (const { repository } of resolved) {
|
|
3119
|
-
if (repositoryAnchors.has(repository.repoRoot)) continue;
|
|
3120
|
-
const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
|
|
3080
|
+
if (payload?.status === "absent") {
|
|
3121
3081
|
const anchored = await anchorRepository(
|
|
3122
|
-
|
|
3082
|
+
client2,
|
|
3123
3083
|
repository,
|
|
3124
|
-
spaceUid
|
|
3125
|
-
agentId
|
|
3126
|
-
);
|
|
3127
|
-
repositoryAnchors.set(repository.repoRoot, {
|
|
3128
|
-
...anchored,
|
|
3129
|
-
repository
|
|
3130
|
-
});
|
|
3131
|
-
}
|
|
3132
|
-
const anchors = [];
|
|
3133
|
-
for (const { ref, repository } of resolved) {
|
|
3134
|
-
const repositoryAnchor = repositoryAnchors.get(repository.repoRoot);
|
|
3135
|
-
if (!repositoryAnchor.uid) continue;
|
|
3136
|
-
const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
|
|
3137
|
-
const anchor = await anchorCodeRef(
|
|
3138
|
-
codeClient,
|
|
3139
|
-
ref,
|
|
3140
|
-
repositoryAnchor.uid,
|
|
3141
|
-
spaceUid,
|
|
3084
|
+
repository.spaceUid ?? `space:agent:${agentId}`,
|
|
3142
3085
|
agentId
|
|
3143
3086
|
);
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
repository: repositoryAnchors.values().next().value,
|
|
3149
|
-
repositories: [...repositoryAnchors.values()],
|
|
3150
|
-
anchors,
|
|
3151
|
-
unresolved,
|
|
3152
|
-
wrote: anchors.some((anchor) => anchor.created)
|
|
3153
|
-
});
|
|
3154
|
-
}
|
|
3155
|
-
case "recall": {
|
|
3156
|
-
const materialized = new Set(anchorUids);
|
|
3157
|
-
let resolution;
|
|
3158
|
-
if (refs.length > 0) {
|
|
3159
|
-
resolution = await adapter.resolveRefs(refs, options);
|
|
3160
|
-
for (const result of resolution.results) {
|
|
3161
|
-
if (!result.resolved) continue;
|
|
3162
|
-
const uid = await resolveMaterializedUid(codeClient, result.resolved, agentId);
|
|
3163
|
-
if (uid) materialized.add(uid);
|
|
3087
|
+
if (anchored?.uid) {
|
|
3088
|
+
names[anchored.uid] = repository.repoId;
|
|
3089
|
+
fresh[repository.repoId] = { uid: anchored.uid, at: stamp };
|
|
3090
|
+
return anchored.uid;
|
|
3164
3091
|
}
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
return ok2({
|
|
3168
|
-
availability: resolution?.availability,
|
|
3169
|
-
anchors: [],
|
|
3170
|
-
context: [],
|
|
3171
|
-
unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
|
|
3172
|
-
});
|
|
3173
|
-
}
|
|
3174
|
-
const context = await Promise.all(
|
|
3175
|
-
[...materialized].map(async (uid) => ({
|
|
3176
|
-
anchor_uid: uid,
|
|
3177
|
-
graph: await codeClient.traverse({
|
|
3178
|
-
action: "neighborhood",
|
|
3179
|
-
start_uid: uid,
|
|
3180
|
-
depth: 2,
|
|
3181
|
-
max_nodes: Math.min(limit ?? 20, 20)
|
|
3182
|
-
})
|
|
3183
|
-
}))
|
|
3184
|
-
);
|
|
3185
|
-
return ok2({
|
|
3186
|
-
availability: resolution?.availability,
|
|
3187
|
-
anchors: [...materialized],
|
|
3188
|
-
context,
|
|
3189
|
-
unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
|
|
3190
|
-
});
|
|
3191
|
-
}
|
|
3192
|
-
case "expand": {
|
|
3193
|
-
const target = await resolveSingleTarget(
|
|
3194
|
-
codeClient,
|
|
3195
|
-
adapter,
|
|
3196
|
-
refs,
|
|
3197
|
-
anchorUids,
|
|
3198
|
-
options
|
|
3199
|
-
);
|
|
3200
|
-
if ("error" in target) return target.error;
|
|
3201
|
-
const expanded = await adapter.expand(target.ref, limit);
|
|
3202
|
-
const joined = await joinMaterialized(
|
|
3203
|
-
codeClient,
|
|
3204
|
-
[...expanded.callers, ...expanded.callees],
|
|
3205
|
-
agentId,
|
|
3206
|
-
Math.min(limit ?? 20, 20)
|
|
3207
|
-
);
|
|
3208
|
-
return ok2({ anchor: target.ref, ...expanded, materialized: joined });
|
|
3209
|
-
}
|
|
3210
|
-
case "affected": {
|
|
3211
|
-
const targetUid = typeof args.task_uid === "string" ? args.task_uid : typeof args.execution_uid === "string" ? args.execution_uid : void 0;
|
|
3212
|
-
let graphContext;
|
|
3213
|
-
const graphRefs = [];
|
|
3214
|
-
let unavailableRepositories = [];
|
|
3215
|
-
if (targetUid) {
|
|
3216
|
-
graphContext = await codeClient.traverse({
|
|
3217
|
-
action: "neighborhood",
|
|
3218
|
-
start_uid: targetUid,
|
|
3219
|
-
depth: 2,
|
|
3220
|
-
max_nodes: 50
|
|
3221
|
-
});
|
|
3222
|
-
const fromGraph = await codeRefsFromGraphContext(
|
|
3223
|
-
codeClient,
|
|
3224
|
-
adapter,
|
|
3225
|
-
graphContext
|
|
3226
|
-
);
|
|
3227
|
-
graphRefs.push(...fromGraph.refs);
|
|
3228
|
-
unavailableRepositories = fromGraph.unavailable;
|
|
3229
|
-
}
|
|
3230
|
-
if (refs.length > 0 || anchorUids.length > 0) {
|
|
3231
|
-
const target = await resolveSingleTarget(
|
|
3232
|
-
codeClient,
|
|
3233
|
-
adapter,
|
|
3234
|
-
refs,
|
|
3235
|
-
anchorUids,
|
|
3236
|
-
options
|
|
3092
|
+
failures.push(
|
|
3093
|
+
`${repository.repoId}: anchor ${anchored?.status ?? "failed"}`
|
|
3237
3094
|
);
|
|
3238
|
-
|
|
3239
|
-
graphRefs.unshift(target.ref);
|
|
3240
|
-
}
|
|
3241
|
-
const unique = uniqueRefs(graphRefs);
|
|
3242
|
-
if (unique.length === 0) {
|
|
3243
|
-
return ok2({
|
|
3244
|
-
target_uid: targetUid,
|
|
3245
|
-
graph_context: graphContext,
|
|
3246
|
-
affected: [],
|
|
3247
|
-
degradation: unavailableRepositories.length > 0 ? `attached code anchors reference repositories unavailable here: ${unavailableRepositories.join(", ")}` : "no materialized code anchors were attached",
|
|
3248
|
-
...unavailableRepositories.length > 0 ? { unavailable_repositories: unavailableRepositories } : {}
|
|
3249
|
-
});
|
|
3095
|
+
return void 0;
|
|
3250
3096
|
}
|
|
3251
|
-
|
|
3252
|
-
|
|
3097
|
+
failures.push(
|
|
3098
|
+
`${repository.repoId}: ${typeof payload?.status === "string" && payload.status ? payload.status : "unresolved"}`
|
|
3253
3099
|
);
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
agentId,
|
|
3259
|
-
Math.min(limit ?? 50, 50)
|
|
3100
|
+
return void 0;
|
|
3101
|
+
} catch (error2) {
|
|
3102
|
+
failures.push(
|
|
3103
|
+
`${repository.repoId}: ${error2?.message || "resolve failed"}`
|
|
3260
3104
|
);
|
|
3261
|
-
return
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3105
|
+
return void 0;
|
|
3106
|
+
}
|
|
3107
|
+
})
|
|
3108
|
+
);
|
|
3109
|
+
if (Object.keys(fresh).length > 0) {
|
|
3110
|
+
writeScopeCache(options.cache, { ...cached, ...fresh });
|
|
3111
|
+
}
|
|
3112
|
+
return {
|
|
3113
|
+
uids: [...new Set(resolved.filter((uid) => Boolean(uid)))],
|
|
3114
|
+
names,
|
|
3115
|
+
failures
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
// src/memory-tool.ts
|
|
3120
|
+
var RESULT_SCHEMA_VERSION = "mindgraph.memory.result.v1";
|
|
3121
|
+
var DEFAULT_OUTPUT_CHARS = 8e3;
|
|
3122
|
+
var MIN_OUTPUT_CHARS = 512;
|
|
3123
|
+
var MAX_OUTPUT_CHARS = 24e3;
|
|
3124
|
+
var HIDDEN_CONTEXT_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
3125
|
+
var HIDDEN_CONTEXT_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
3126
|
+
var MEMORY_TOOL = {
|
|
3127
|
+
name: "mindgraph_memory",
|
|
3128
|
+
description: "Read the portable MindGraph memory surface. Use action='context' with mode='resume' or 'continuity' for authoritative task-first work state, and mode='topic' with a short keyword query for prior knowledge relevant to the user's request. Use action='status' to inspect integration capabilities and limitations. This tool never writes; durable capture and correction use the existing typed MindGraph write tools.",
|
|
3129
|
+
inputSchema: {
|
|
3130
|
+
type: "object",
|
|
3131
|
+
properties: {
|
|
3132
|
+
action: {
|
|
3133
|
+
type: "string",
|
|
3134
|
+
enum: ["status", "context"],
|
|
3135
|
+
description: "Read integration status or bounded memory context"
|
|
3136
|
+
},
|
|
3137
|
+
mode: {
|
|
3138
|
+
type: "string",
|
|
3139
|
+
enum: ["topic", "continuity", "resume"],
|
|
3140
|
+
description: "Context strategy. topic uses query-shaped retrieval; continuity/resume use authoritative task-first resume_work."
|
|
3141
|
+
},
|
|
3142
|
+
query: {
|
|
3143
|
+
type: "string",
|
|
3144
|
+
description: "Required for mode='topic': 1-3 discriminating BM25 keywords, not a full sentence"
|
|
3145
|
+
},
|
|
3146
|
+
project_uid: { type: "string", description: "Optional project scope" },
|
|
3147
|
+
task_uid: { type: "string", description: "Optional task scope for resume context" },
|
|
3148
|
+
session_uid: { type: "string", description: "Optional durable session scope" },
|
|
3149
|
+
scope_uids: {
|
|
3150
|
+
type: "array",
|
|
3151
|
+
items: { type: "string" },
|
|
3152
|
+
description: "Optional explicit graph scopes for continuity/resume"
|
|
3153
|
+
},
|
|
3154
|
+
scope: {
|
|
3155
|
+
type: "string",
|
|
3156
|
+
enum: ["workspace"],
|
|
3157
|
+
description: "For continuity/resume on a local server: select work across every repository the working directory's .mindgraph/workspace.json declares, and list the other eligible tasks grouped by repository"
|
|
3158
|
+
},
|
|
3159
|
+
node_types: {
|
|
3160
|
+
type: "array",
|
|
3161
|
+
items: { type: "string" },
|
|
3162
|
+
description: "Optional node-type filter for topic context"
|
|
3163
|
+
},
|
|
3164
|
+
layer: {
|
|
3165
|
+
type: "string",
|
|
3166
|
+
enum: ["reality", "epistemic", "intent", "action", "memory", "agent"],
|
|
3167
|
+
description: "Optional cognitive-layer filter for topic context"
|
|
3168
|
+
},
|
|
3169
|
+
limit: {
|
|
3170
|
+
type: "integer",
|
|
3171
|
+
minimum: 1,
|
|
3172
|
+
maximum: 50,
|
|
3173
|
+
default: 8,
|
|
3174
|
+
description: "Maximum direct graph items requested before bounded expansion"
|
|
3175
|
+
},
|
|
3176
|
+
include_chunks: {
|
|
3177
|
+
type: "boolean",
|
|
3178
|
+
default: false,
|
|
3179
|
+
description: "Include bounded source excerpts when topic summaries are insufficient"
|
|
3180
|
+
},
|
|
3181
|
+
include_documents: {
|
|
3182
|
+
type: "boolean",
|
|
3183
|
+
default: false,
|
|
3184
|
+
description: "Include bounded knowledge articles for topic context"
|
|
3185
|
+
},
|
|
3186
|
+
valid_at: {
|
|
3187
|
+
type: "string",
|
|
3188
|
+
description: "Optional ISO timestamp for time-aware topic retrieval"
|
|
3189
|
+
},
|
|
3190
|
+
graph_expansion_limit: {
|
|
3191
|
+
type: "integer",
|
|
3192
|
+
minimum: 0,
|
|
3193
|
+
maximum: 20,
|
|
3194
|
+
default: 3,
|
|
3195
|
+
description: "Bounded graph neighbors added after direct topic matches"
|
|
3196
|
+
},
|
|
3197
|
+
graph_max_depth: {
|
|
3198
|
+
type: "integer",
|
|
3199
|
+
minimum: 0,
|
|
3200
|
+
maximum: 5,
|
|
3201
|
+
default: 2,
|
|
3202
|
+
description: "Maximum graph-expansion depth for topic context"
|
|
3203
|
+
},
|
|
3204
|
+
max_output_chars: {
|
|
3205
|
+
type: "integer",
|
|
3206
|
+
minimum: MIN_OUTPUT_CHARS,
|
|
3207
|
+
maximum: MAX_OUTPUT_CHARS,
|
|
3208
|
+
default: DEFAULT_OUTPUT_CHARS,
|
|
3209
|
+
description: "Hard character budget for model-ready context; whole items are retained or omitted"
|
|
3210
|
+
},
|
|
3211
|
+
agent_id: { type: "string", description: "Agent identity" }
|
|
3212
|
+
},
|
|
3213
|
+
required: ["action"]
|
|
3214
|
+
},
|
|
3215
|
+
outputSchema: {
|
|
3216
|
+
type: "object",
|
|
3217
|
+
properties: {
|
|
3218
|
+
schema_version: { type: "string", const: RESULT_SCHEMA_VERSION },
|
|
3219
|
+
action: { type: "string", enum: ["status", "context"] },
|
|
3220
|
+
profile: { type: "string" },
|
|
3221
|
+
server: { type: "object" },
|
|
3222
|
+
integration: { type: "object" },
|
|
3223
|
+
capabilities: { type: "object" },
|
|
3224
|
+
degradation: { type: "array", items: { type: "object" } },
|
|
3225
|
+
context_id: { type: "string" },
|
|
3226
|
+
mode: { type: "string", enum: ["topic", "continuity", "resume"] },
|
|
3227
|
+
scope: { type: "object" },
|
|
3228
|
+
rendered_context: { type: "string" },
|
|
3229
|
+
rendered_hash: { type: "string" },
|
|
3230
|
+
items: { type: "array", items: { type: "object" } },
|
|
3231
|
+
retrieval_trace: { type: "object" },
|
|
3232
|
+
budget: { type: "object" },
|
|
3233
|
+
freshness: { type: "object" },
|
|
3234
|
+
warnings: { type: "array", items: { type: "object" } }
|
|
3235
|
+
},
|
|
3236
|
+
required: ["schema_version", "action"],
|
|
3237
|
+
oneOf: [
|
|
3238
|
+
{
|
|
3239
|
+
properties: { action: { const: "status" } },
|
|
3240
|
+
required: ["profile", "server", "integration", "scope", "capabilities", "degradation"]
|
|
3241
|
+
},
|
|
3242
|
+
{
|
|
3243
|
+
properties: { action: { const: "context" } },
|
|
3244
|
+
required: [
|
|
3245
|
+
"context_id",
|
|
3246
|
+
"mode",
|
|
3247
|
+
"scope",
|
|
3248
|
+
"rendered_context",
|
|
3249
|
+
"rendered_hash",
|
|
3250
|
+
"items",
|
|
3251
|
+
"retrieval_trace",
|
|
3252
|
+
"budget",
|
|
3253
|
+
"freshness",
|
|
3254
|
+
"warnings"
|
|
3255
|
+
]
|
|
3268
3256
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
return toolError(cause, "code_tool_failed");
|
|
3257
|
+
]
|
|
3258
|
+
},
|
|
3259
|
+
annotations: {
|
|
3260
|
+
readOnlyHint: true,
|
|
3261
|
+
destructiveHint: false,
|
|
3262
|
+
idempotentHint: true,
|
|
3263
|
+
openWorldHint: false
|
|
3277
3264
|
}
|
|
3265
|
+
};
|
|
3266
|
+
function obj2(value) {
|
|
3267
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3278
3268
|
}
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3269
|
+
function text(value) {
|
|
3270
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3271
|
+
}
|
|
3272
|
+
function stableJson2(value) {
|
|
3273
|
+
if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
|
|
3274
|
+
if (value && typeof value === "object") {
|
|
3275
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson2(item)}`).join(",")}}`;
|
|
3282
3276
|
}
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3277
|
+
return JSON.stringify(value);
|
|
3278
|
+
}
|
|
3279
|
+
function sha256(value) {
|
|
3280
|
+
return (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex");
|
|
3281
|
+
}
|
|
3282
|
+
function outputBudget(value) {
|
|
3283
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_OUTPUT_CHARS;
|
|
3284
|
+
return Math.min(MAX_OUTPUT_CHARS, Math.max(MIN_OUTPUT_CHARS, Math.floor(value)));
|
|
3285
|
+
}
|
|
3286
|
+
function defined(values) {
|
|
3287
|
+
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
|
|
3288
|
+
}
|
|
3289
|
+
function memoryStatus(config = {}) {
|
|
3290
|
+
return {
|
|
3291
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
3292
|
+
action: "status",
|
|
3293
|
+
profile: "M0",
|
|
3294
|
+
server: defined({
|
|
3295
|
+
name: "mindgraph-mcp",
|
|
3296
|
+
version: config.serverVersion ?? "unknown",
|
|
3297
|
+
base_url: config.baseUrl
|
|
3298
|
+
}),
|
|
3299
|
+
integration: {
|
|
3300
|
+
adapter_state: "model_controlled",
|
|
3301
|
+
harness: config.harness ?? "generic",
|
|
3302
|
+
configured_tool_profile: config.profile ?? "general",
|
|
3303
|
+
automatic_capture: false,
|
|
3304
|
+
automatic_delivery: false,
|
|
3305
|
+
delivery_verification: "unsupported",
|
|
3306
|
+
curator_mode: "disabled"
|
|
3307
|
+
},
|
|
3308
|
+
scope: defined({ org_id: config.orgId, agent_id: config.agentId }),
|
|
3309
|
+
capabilities: {
|
|
3310
|
+
status: true,
|
|
3311
|
+
topic_context: true,
|
|
3312
|
+
authoritative_resume_context: true,
|
|
3313
|
+
bounded_rendering: true,
|
|
3314
|
+
structured_content: true,
|
|
3315
|
+
typed_explicit_writes: true,
|
|
3316
|
+
lifecycle_event_ingest: false,
|
|
3317
|
+
automatic_context_injection: false,
|
|
3318
|
+
curator_mutation: false
|
|
3319
|
+
},
|
|
3320
|
+
degradation: [
|
|
3321
|
+
{
|
|
3322
|
+
code: "automatic_capture_unavailable",
|
|
3323
|
+
message: "M0 does not observe host lifecycle events; explicit typed write tools remain available."
|
|
3324
|
+
},
|
|
3325
|
+
{
|
|
3326
|
+
code: "delivery_unverified",
|
|
3327
|
+
message: "A successful MCP read does not prove that the host injected or used the returned context."
|
|
3328
|
+
},
|
|
3329
|
+
{
|
|
3330
|
+
code: "curator_disabled",
|
|
3331
|
+
message: "Curator proposals and autonomous mutation are not enabled in M0."
|
|
3291
3332
|
}
|
|
3292
|
-
|
|
3333
|
+
]
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
3336
|
+
function nodeType(node) {
|
|
3337
|
+
const raw = node.node_type;
|
|
3338
|
+
if (typeof raw === "string") return raw;
|
|
3339
|
+
return text(obj2(raw)?.Custom) ?? "Node";
|
|
3340
|
+
}
|
|
3341
|
+
function compactItem(raw, fallbackType) {
|
|
3342
|
+
const wrapper = obj2(raw);
|
|
3343
|
+
if (!wrapper) return void 0;
|
|
3344
|
+
const value = obj2(wrapper.node) ?? obj2(wrapper.object) ?? wrapper;
|
|
3345
|
+
const uid = text(value.uid) ?? text(value.chunk_uid);
|
|
3346
|
+
if (!uid) return void 0;
|
|
3347
|
+
return defined({
|
|
3348
|
+
uid,
|
|
3349
|
+
type: fallbackType ?? nodeType(value),
|
|
3350
|
+
label: text(value.label) ?? text(value.document_title),
|
|
3351
|
+
truth_status: text(value.truth_status) ?? text(obj2(value.props)?.truth_status),
|
|
3352
|
+
// `true` from /retrieve, an object naming the replacement from /retrieve/context.
|
|
3353
|
+
superseded: value.superseded ? true : void 0,
|
|
3354
|
+
currently_valid: value.currently_valid === false ? false : void 0,
|
|
3355
|
+
valid_at_time: value.valid_at_time === false ? false : void 0,
|
|
3356
|
+
retrieval_origin: text(value.retrieval_origin),
|
|
3357
|
+
retrieval_depth: typeof value.retrieval_depth === "number" ? value.retrieval_depth : void 0
|
|
3358
|
+
});
|
|
3359
|
+
}
|
|
3360
|
+
function topicCandidates(raw) {
|
|
3361
|
+
const payload = obj2(raw);
|
|
3362
|
+
if (!payload) return [];
|
|
3363
|
+
const graph = obj2(payload.graph);
|
|
3364
|
+
const items = [];
|
|
3365
|
+
for (const article of Array.isArray(payload.articles) ? payload.articles : []) {
|
|
3366
|
+
const item = compactItem(article, "Article");
|
|
3367
|
+
if (item) items.push(item);
|
|
3293
3368
|
}
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
const
|
|
3311
|
-
|
|
3312
|
-
|
|
3369
|
+
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
3370
|
+
const labels = /* @__PURE__ */ new Map();
|
|
3371
|
+
for (const node of rawNodes) {
|
|
3372
|
+
const item = compactItem(node);
|
|
3373
|
+
if (item) {
|
|
3374
|
+
if (HIDDEN_CONTEXT_NODE_TYPES.has(text(item.type) ?? "")) continue;
|
|
3375
|
+
items.push(item);
|
|
3376
|
+
const uid = text(item.uid);
|
|
3377
|
+
const label = text(item.label);
|
|
3378
|
+
if (uid && label) labels.set(uid, label);
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
for (const rawEdge of Array.isArray(graph?.edges) ? graph.edges : []) {
|
|
3382
|
+
const edge = obj2(rawEdge);
|
|
3383
|
+
const fromUid = text(edge?.from_uid);
|
|
3384
|
+
const toUid = text(edge?.to_uid);
|
|
3385
|
+
const edgeType = text(edge?.edge_type) ?? text(obj2(edge?.edge_type)?.Custom);
|
|
3386
|
+
if (!fromUid || !toUid || !edgeType || HIDDEN_CONTEXT_EDGE_TYPES.has(edgeType) || !labels.has(fromUid) || !labels.has(toUid)) {
|
|
3387
|
+
continue;
|
|
3388
|
+
}
|
|
3389
|
+
items.push(
|
|
3390
|
+
defined({
|
|
3391
|
+
type: "Relationship",
|
|
3392
|
+
from_uid: fromUid,
|
|
3393
|
+
to_uid: toUid,
|
|
3394
|
+
edge_type: edgeType,
|
|
3395
|
+
from_label: labels.get(fromUid),
|
|
3396
|
+
to_label: labels.get(toUid)
|
|
3397
|
+
})
|
|
3313
3398
|
);
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3399
|
+
}
|
|
3400
|
+
for (const chunk of Array.isArray(payload.chunks) ? payload.chunks : []) {
|
|
3401
|
+
const item = compactItem(chunk, "SourceExcerpt");
|
|
3402
|
+
if (item) items.push(item);
|
|
3403
|
+
}
|
|
3404
|
+
return items;
|
|
3405
|
+
}
|
|
3406
|
+
function resumeCandidates(raw) {
|
|
3407
|
+
const payload = obj2(raw);
|
|
3408
|
+
if (!payload) return [];
|
|
3409
|
+
const items = [];
|
|
3410
|
+
for (const key of ["task", "goal", "project", "plan", "active_execution", "lease"]) {
|
|
3411
|
+
const item = compactItem(payload[key], key);
|
|
3412
|
+
if (item) items.push(item);
|
|
3413
|
+
}
|
|
3414
|
+
for (const value of Array.isArray(payload.other_eligible) ? payload.other_eligible : []) {
|
|
3415
|
+
const item = compactItem(value, "Task");
|
|
3416
|
+
if (item) items.push(item);
|
|
3417
|
+
}
|
|
3418
|
+
for (const key of ["next_steps", "recent_executions", "blockers", "code_targets"]) {
|
|
3419
|
+
for (const value of Array.isArray(payload[key]) ? payload[key] : []) {
|
|
3420
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
3421
|
+
if (item) items.push(item);
|
|
3331
3422
|
}
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
}
|
|
3339
|
-
});
|
|
3423
|
+
}
|
|
3424
|
+
const knowledge = obj2(payload.knowledge);
|
|
3425
|
+
for (const key of ["lessons", "risks"]) {
|
|
3426
|
+
for (const value of Array.isArray(knowledge?.[key]) ? knowledge[key] : []) {
|
|
3427
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
3428
|
+
if (item) items.push(item);
|
|
3340
3429
|
}
|
|
3341
3430
|
}
|
|
3342
|
-
return
|
|
3431
|
+
return items;
|
|
3343
3432
|
}
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
}
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3433
|
+
function visibleItems(candidates, rendered2) {
|
|
3434
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3435
|
+
return candidates.filter((item) => {
|
|
3436
|
+
const uid = text(item.uid);
|
|
3437
|
+
if (uid) {
|
|
3438
|
+
if (seen.has(uid) || !rendered2.includes(`[${uid}]`)) return false;
|
|
3439
|
+
seen.add(uid);
|
|
3440
|
+
return true;
|
|
3441
|
+
}
|
|
3442
|
+
if (item.type === "Relationship") {
|
|
3443
|
+
const from = text(item.from_label);
|
|
3444
|
+
const to = text(item.to_label);
|
|
3445
|
+
const edgeType = text(item.edge_type);
|
|
3446
|
+
if (!from || !to || !edgeType) return false;
|
|
3447
|
+
const key = `${text(item.from_uid)}:${edgeType}:${text(item.to_uid)}`;
|
|
3448
|
+
if (seen.has(key) || !rendered2.includes(`${from} \u2014${edgeType}\u2192 ${to}`)) return false;
|
|
3449
|
+
seen.add(key);
|
|
3450
|
+
return true;
|
|
3451
|
+
}
|
|
3452
|
+
return false;
|
|
3360
3453
|
});
|
|
3361
3454
|
}
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3455
|
+
function latestTimestamp(value) {
|
|
3456
|
+
let latest;
|
|
3457
|
+
const visit = (current) => {
|
|
3458
|
+
if (Array.isArray(current)) {
|
|
3459
|
+
for (const item of current) visit(item);
|
|
3460
|
+
return;
|
|
3461
|
+
}
|
|
3462
|
+
const record2 = obj2(current);
|
|
3463
|
+
if (!record2) return;
|
|
3464
|
+
for (const [key, item] of Object.entries(record2)) {
|
|
3465
|
+
if (["updated_at", "created_at", "completed_at", "started_at", "observed_at"].includes(key) && typeof item === "string" && !Number.isNaN(Date.parse(item)) && (!latest || Date.parse(item) > Date.parse(latest))) {
|
|
3466
|
+
latest = item;
|
|
3467
|
+
}
|
|
3468
|
+
visit(item);
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3471
|
+
visit(value);
|
|
3472
|
+
return latest;
|
|
3473
|
+
}
|
|
3474
|
+
function contextWarnings(raw, rendered2, available, returned) {
|
|
3475
|
+
const warnings = [
|
|
3476
|
+
{
|
|
3477
|
+
code: "delivery_unverified",
|
|
3478
|
+
message: "The MCP server returned this context but cannot verify that the host injected or used it."
|
|
3479
|
+
}
|
|
3480
|
+
];
|
|
3481
|
+
const serialized = JSON.stringify(raw);
|
|
3482
|
+
if (available > returned || rendered2.includes("item(s) omitted")) {
|
|
3483
|
+
warnings.push({
|
|
3484
|
+
code: "context_bounded",
|
|
3485
|
+
message: `${Math.max(0, available - returned)} structured item(s) were omitted from the rendered context.`
|
|
3391
3486
|
});
|
|
3392
3487
|
}
|
|
3393
|
-
|
|
3488
|
+
if (/"superseded":(?:true|\{)/.test(serialized)) {
|
|
3489
|
+
warnings.push({ code: "superseded_items_present", message: "Some retrieved items are superseded." });
|
|
3490
|
+
}
|
|
3491
|
+
if (/"currently_valid":false|"valid_at_time":false/.test(serialized)) {
|
|
3492
|
+
warnings.push({
|
|
3493
|
+
code: "validity_warning",
|
|
3494
|
+
message: "Some retrieved items are outside their current or requested validity window."
|
|
3495
|
+
});
|
|
3496
|
+
}
|
|
3497
|
+
const payload = obj2(raw);
|
|
3498
|
+
if (payload?.truncated === true || obj2(payload?.truncation)) {
|
|
3499
|
+
const truncation = obj2(payload?.truncation);
|
|
3500
|
+
if (payload?.truncated === true || Object.values(truncation ?? {}).some(Boolean)) {
|
|
3501
|
+
warnings.push({ code: "source_truncated", message: "The authoritative source reported truncated fields." });
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
if (text(payload?.warning)) {
|
|
3505
|
+
warnings.push({ code: "source_warning", message: text(payload?.warning) });
|
|
3506
|
+
}
|
|
3507
|
+
return warnings;
|
|
3394
3508
|
}
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
key_version: 1,
|
|
3401
|
-
key: codeRefIdentityKey(ref)
|
|
3402
|
-
},
|
|
3403
|
-
agent_id: agentId
|
|
3404
|
-
});
|
|
3405
|
-
return response.status === "existing" ? response.uid : void 0;
|
|
3509
|
+
function error(message) {
|
|
3510
|
+
return {
|
|
3511
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
3512
|
+
isError: true
|
|
3513
|
+
};
|
|
3406
3514
|
}
|
|
3407
|
-
async function
|
|
3408
|
-
const
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3515
|
+
async function handleMemoryTool(client2, args, config = {}) {
|
|
3516
|
+
const action = text(args.action);
|
|
3517
|
+
if (action === "status") {
|
|
3518
|
+
const status = memoryStatus({ ...config, agentId: text(args.agent_id) ?? config.agentId });
|
|
3519
|
+
return {
|
|
3520
|
+
content: [{ type: "text", text: JSON.stringify(status) }],
|
|
3521
|
+
structuredContent: status
|
|
3522
|
+
};
|
|
3523
|
+
}
|
|
3524
|
+
if (action !== "context") {
|
|
3525
|
+
return error("action must be 'status' or 'context'");
|
|
3526
|
+
}
|
|
3527
|
+
const mode = text(args.mode) ?? (text(args.query) ? "topic" : void 0);
|
|
3528
|
+
if (!mode || !["topic", "continuity", "resume"].includes(mode)) {
|
|
3529
|
+
return error("action='context' requires mode='topic', 'continuity', or 'resume'");
|
|
3530
|
+
}
|
|
3531
|
+
const budget = outputBudget(args.max_output_chars);
|
|
3532
|
+
const agentId = text(args.agent_id) ?? config.agentId;
|
|
3533
|
+
let raw;
|
|
3534
|
+
let rendered2;
|
|
3535
|
+
let strategy;
|
|
3536
|
+
let candidates;
|
|
3537
|
+
let workspace;
|
|
3538
|
+
if (mode === "topic") {
|
|
3539
|
+
const query = text(args.query);
|
|
3540
|
+
if (!query) return error("mode='topic' requires a non-empty query of 1-3 discriminating keywords");
|
|
3541
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.min(50, Math.max(1, Math.floor(args.limit))) : 8;
|
|
3542
|
+
const request = defined({
|
|
3543
|
+
query,
|
|
3544
|
+
project_uid: text(args.project_uid),
|
|
3545
|
+
node_limit: limit,
|
|
3546
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
3547
|
+
layer: text(args.layer),
|
|
3548
|
+
chunk_limit: args.include_chunks === true ? limit : 0,
|
|
3549
|
+
article_limit: args.include_documents === true ? limit : 0,
|
|
3550
|
+
valid_at: text(args.valid_at),
|
|
3551
|
+
include_graph: true,
|
|
3552
|
+
graph_expansion_limit: typeof args.graph_expansion_limit === "number" ? args.graph_expansion_limit : 3,
|
|
3553
|
+
graph_max_depth: typeof args.graph_max_depth === "number" ? args.graph_max_depth : 2
|
|
3554
|
+
});
|
|
3555
|
+
raw = await client2.retrieveContext(request);
|
|
3556
|
+
rendered2 = renderContext(raw, budget) ?? "No results found for this search.";
|
|
3557
|
+
strategy = "retrieve_context";
|
|
3558
|
+
candidates = topicCandidates(raw);
|
|
3559
|
+
} else {
|
|
3560
|
+
if (args.scope !== void 0 && args.scope !== "workspace") {
|
|
3561
|
+
return error("scope must be 'workspace' when given");
|
|
3419
3562
|
}
|
|
3420
|
-
|
|
3563
|
+
if (args.scope === "workspace") {
|
|
3564
|
+
if (!config.resolveWorkspaceScope) {
|
|
3565
|
+
return error(
|
|
3566
|
+
"scope='workspace' needs the local MindGraph MCP server, which reads .mindgraph/workspace.json beside the checkout; this server has no working directory. Pass scope_uids instead."
|
|
3567
|
+
);
|
|
3568
|
+
}
|
|
3569
|
+
workspace = await config.resolveWorkspaceScope(agentId ?? "mcp");
|
|
3570
|
+
if (workspace.uids.length === 0) {
|
|
3571
|
+
return error(
|
|
3572
|
+
`scope='workspace' resolved no repositories${workspace.failures.length > 0 ? ` (${workspace.failures.join("; ")})` : ""}`
|
|
3573
|
+
);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
const scopeUids = Array.from(
|
|
3577
|
+
/* @__PURE__ */ new Set([
|
|
3578
|
+
...Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : [],
|
|
3579
|
+
...text(args.project_uid) ? [text(args.project_uid)] : [],
|
|
3580
|
+
...workspace?.uids ?? []
|
|
3581
|
+
])
|
|
3582
|
+
);
|
|
3583
|
+
raw = await client2.plan(
|
|
3584
|
+
defined({
|
|
3585
|
+
action: "resume_work",
|
|
3586
|
+
task_uid: text(args.task_uid),
|
|
3587
|
+
session_uid: text(args.session_uid),
|
|
3588
|
+
scope_uids: scopeUids.length > 0 ? scopeUids : void 0,
|
|
3589
|
+
limit: workspace ? WORKSPACE_RESUME_LIMIT : 1,
|
|
3590
|
+
agent_id: agentId
|
|
3591
|
+
})
|
|
3592
|
+
);
|
|
3593
|
+
rendered2 = renderResumeContext(raw, budget, workspace?.names) ?? "No eligible work was found in the requested scope.";
|
|
3594
|
+
strategy = "resume_work";
|
|
3595
|
+
candidates = resumeCandidates(raw);
|
|
3421
3596
|
}
|
|
3597
|
+
const items = visibleItems(candidates, rendered2);
|
|
3598
|
+
const renderedHash = sha256(rendered2);
|
|
3599
|
+
const scope = defined({
|
|
3600
|
+
org_id: config.orgId,
|
|
3601
|
+
agent_id: agentId,
|
|
3602
|
+
harness: config.harness ?? "generic",
|
|
3603
|
+
project_uid: text(args.project_uid),
|
|
3604
|
+
task_uid: text(args.task_uid),
|
|
3605
|
+
session_uid: text(args.session_uid),
|
|
3606
|
+
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0,
|
|
3607
|
+
workspace_repositories: workspace ? Object.values(workspace.names).sort() : void 0
|
|
3608
|
+
});
|
|
3609
|
+
const contextId = `ctx_${sha256(
|
|
3610
|
+
stableJson2({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
3611
|
+
).slice(0, 24)}`;
|
|
3612
|
+
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
3613
|
+
const result = {
|
|
3614
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
3615
|
+
action: "context",
|
|
3616
|
+
context_id: contextId,
|
|
3617
|
+
mode,
|
|
3618
|
+
scope,
|
|
3619
|
+
rendered_context: rendered2,
|
|
3620
|
+
rendered_hash: renderedHash,
|
|
3621
|
+
items,
|
|
3622
|
+
retrieval_trace: defined({
|
|
3623
|
+
strategy,
|
|
3624
|
+
query: text(args.query),
|
|
3625
|
+
project_uid: text(args.project_uid),
|
|
3626
|
+
task_uid: text(args.task_uid),
|
|
3627
|
+
session_uid: text(args.session_uid),
|
|
3628
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
3629
|
+
graph_expansion_limit: mode === "topic" ? args.graph_expansion_limit ?? 3 : void 0,
|
|
3630
|
+
graph_max_depth: mode === "topic" ? args.graph_max_depth ?? 2 : void 0,
|
|
3631
|
+
available_items: candidates.length,
|
|
3632
|
+
returned_items: items.length,
|
|
3633
|
+
omitted_items: Math.max(0, candidates.length - items.length)
|
|
3634
|
+
}),
|
|
3635
|
+
budget: {
|
|
3636
|
+
unit: "characters",
|
|
3637
|
+
requested_chars: budget,
|
|
3638
|
+
used_chars: rendered2.length,
|
|
3639
|
+
available_items: candidates.length,
|
|
3640
|
+
returned_items: items.length,
|
|
3641
|
+
omitted_items: Math.max(0, candidates.length - items.length),
|
|
3642
|
+
bounded
|
|
3643
|
+
},
|
|
3644
|
+
freshness: defined({
|
|
3645
|
+
valid_at: text(args.valid_at),
|
|
3646
|
+
latest_source_timestamp: latestTimestamp(raw)
|
|
3647
|
+
}),
|
|
3648
|
+
warnings: [
|
|
3649
|
+
...contextWarnings(raw, rendered2, candidates.length, items.length),
|
|
3650
|
+
...workspace && workspace.failures.length > 0 ? [
|
|
3651
|
+
{
|
|
3652
|
+
code: "workspace_scope_partial",
|
|
3653
|
+
message: `${workspace.failures.length} declared repositories did not resolve and were left out: ${workspace.failures.join("; ")}`
|
|
3654
|
+
}
|
|
3655
|
+
] : []
|
|
3656
|
+
]
|
|
3657
|
+
};
|
|
3658
|
+
return {
|
|
3659
|
+
content: [{ type: "text", text: rendered2 }],
|
|
3660
|
+
structuredContent: result
|
|
3661
|
+
};
|
|
3422
3662
|
}
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3663
|
+
|
|
3664
|
+
// src/resources.ts
|
|
3665
|
+
var RESOURCES = [
|
|
3666
|
+
{
|
|
3667
|
+
uri: "mindgraph://memory/status",
|
|
3668
|
+
name: "Memory Integration Status",
|
|
3669
|
+
description: "Portable memory profile, adapter state, supported capabilities, and explicit limitations",
|
|
3670
|
+
mimeType: "application/json"
|
|
3671
|
+
},
|
|
3672
|
+
{
|
|
3673
|
+
uri: "mindgraph://stats",
|
|
3674
|
+
name: "Graph Statistics",
|
|
3675
|
+
description: "Current knowledge graph statistics: node counts, edge counts, and layer distribution",
|
|
3676
|
+
mimeType: "application/json"
|
|
3677
|
+
},
|
|
3678
|
+
{
|
|
3679
|
+
uri: "mindgraph://goals",
|
|
3680
|
+
name: "Active Goals",
|
|
3681
|
+
description: "All active goals in the knowledge graph",
|
|
3682
|
+
mimeType: "application/json"
|
|
3683
|
+
},
|
|
3684
|
+
{
|
|
3685
|
+
uri: "mindgraph://questions",
|
|
3686
|
+
name: "Open Questions",
|
|
3687
|
+
description: "All open questions in the knowledge graph",
|
|
3688
|
+
mimeType: "application/json"
|
|
3689
|
+
},
|
|
3690
|
+
{
|
|
3691
|
+
uri: "mindgraph://contradictions",
|
|
3692
|
+
name: "Contradictions",
|
|
3693
|
+
description: "Contradictory claims in the knowledge graph",
|
|
3694
|
+
mimeType: "application/json"
|
|
3695
|
+
},
|
|
3696
|
+
{
|
|
3697
|
+
uri: "mindgraph://decisions",
|
|
3698
|
+
name: "Open Decisions",
|
|
3699
|
+
description: "Unresolved decisions awaiting resolution",
|
|
3700
|
+
mimeType: "application/json"
|
|
3444
3701
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
}
|
|
3702
|
+
];
|
|
3703
|
+
var RESOURCE_TEMPLATES = [
|
|
3704
|
+
{
|
|
3705
|
+
uriTemplate: "mindgraph://node/{uid}",
|
|
3706
|
+
name: "Graph Node",
|
|
3707
|
+
description: "Retrieve a specific node by its UID, including all properties, edges, and version history",
|
|
3708
|
+
mimeType: "application/json"
|
|
3709
|
+
},
|
|
3710
|
+
{
|
|
3711
|
+
uriTemplate: "mindgraph://search/{query}",
|
|
3712
|
+
name: "Search Results",
|
|
3713
|
+
description: "BM25 keyword search across all nodes \u2014 pass 1\u20133 discriminating terms (e.g. 'Kissinger NATO'), not natural language sentences",
|
|
3714
|
+
mimeType: "application/json"
|
|
3715
|
+
},
|
|
3716
|
+
{
|
|
3717
|
+
uriTemplate: "mindgraph://layer/{layer}",
|
|
3718
|
+
name: "Layer Nodes",
|
|
3719
|
+
description: "List all nodes in a specific cognitive layer (reality, epistemic, intent, action, memory, agent)",
|
|
3720
|
+
mimeType: "application/json"
|
|
3455
3721
|
}
|
|
3456
|
-
|
|
3722
|
+
];
|
|
3723
|
+
var RESOURCE_GOVERNANCE_TOOL = "mindgraph_retrieve";
|
|
3724
|
+
function json(uri, data) {
|
|
3725
|
+
return {
|
|
3726
|
+
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
|
|
3727
|
+
};
|
|
3457
3728
|
}
|
|
3458
|
-
async function
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
});
|
|
3729
|
+
async function readResource(client2, uri, memoryConfig = {}) {
|
|
3730
|
+
switch (uri) {
|
|
3731
|
+
case "mindgraph://memory/status":
|
|
3732
|
+
return json(uri, memoryStatus(memoryConfig));
|
|
3733
|
+
case "mindgraph://stats":
|
|
3734
|
+
return json(uri, await client2.stats());
|
|
3735
|
+
case "mindgraph://goals":
|
|
3736
|
+
return json(uri, await client2.getGoals());
|
|
3737
|
+
case "mindgraph://questions":
|
|
3738
|
+
return json(uri, await client2.getOpenQuestions());
|
|
3739
|
+
case "mindgraph://contradictions":
|
|
3740
|
+
return json(uri, await client2.getContradictions());
|
|
3741
|
+
case "mindgraph://decisions":
|
|
3742
|
+
return json(uri, await client2.getOpenDecisions());
|
|
3473
3743
|
}
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
const stored = nodes.flatMap((node) => {
|
|
3482
|
-
if (!node) return [];
|
|
3483
|
-
const attributes = node.props?.attributes;
|
|
3484
|
-
if (!attributes || typeof attributes !== "object") return [];
|
|
3485
|
-
const codeRef = attributes.code_ref;
|
|
3486
|
-
return isStoredCodeRef(codeRef) ? [codeRef] : [];
|
|
3487
|
-
});
|
|
3488
|
-
const refs = [];
|
|
3489
|
-
const unavailable = /* @__PURE__ */ new Set();
|
|
3490
|
-
for (const ref of stored) {
|
|
3491
|
-
try {
|
|
3492
|
-
const repository = await adapter.resolveRepository(ref.repoId);
|
|
3493
|
-
refs.push({ ...ref, repoRoot: repository.repoRoot });
|
|
3494
|
-
} catch (cause) {
|
|
3495
|
-
if (cause instanceof UnknownRepositoryError) {
|
|
3496
|
-
unavailable.add(ref.repoId);
|
|
3497
|
-
} else {
|
|
3498
|
-
throw cause;
|
|
3499
|
-
}
|
|
3500
|
-
}
|
|
3744
|
+
const nodeMatch = uri.match(/^mindgraph:\/\/node\/(.+)$/);
|
|
3745
|
+
if (nodeMatch) {
|
|
3746
|
+
const uid = decodeURIComponent(nodeMatch[1]);
|
|
3747
|
+
const node = await client2.getNode(uid);
|
|
3748
|
+
const edges = await client2.getEdges({ from_uid: uid });
|
|
3749
|
+
const inEdges = await client2.getEdges({ to_uid: uid });
|
|
3750
|
+
return json(uri, { node, outgoing_edges: edges, incoming_edges: inEdges });
|
|
3501
3751
|
}
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
value.forEach((item) => collectUids(item, uids));
|
|
3507
|
-
return;
|
|
3752
|
+
const searchMatch = uri.match(/^mindgraph:\/\/search\/(.+)$/);
|
|
3753
|
+
if (searchMatch) {
|
|
3754
|
+
const query = decodeURIComponent(searchMatch[1]);
|
|
3755
|
+
return json(uri, await client2.search(query, { limit: 20 }));
|
|
3508
3756
|
}
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
} else {
|
|
3514
|
-
collectUids(child, uids);
|
|
3515
|
-
}
|
|
3757
|
+
const layerMatch = uri.match(/^mindgraph:\/\/layer\/(.+)$/);
|
|
3758
|
+
if (layerMatch) {
|
|
3759
|
+
const layer = decodeURIComponent(layerMatch[1]);
|
|
3760
|
+
return json(uri, await client2.getNodes({ layer, limit: 50 }));
|
|
3516
3761
|
}
|
|
3762
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
3517
3763
|
}
|
|
3518
|
-
function
|
|
3519
|
-
|
|
3520
|
-
const
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
return
|
|
3530
|
-
const key = `${ref.repoId}:${ref.path}:${ref.qualifiedName}:${ref.signature ?? ""}`;
|
|
3531
|
-
if (seen.has(key)) return false;
|
|
3532
|
-
seen.add(key);
|
|
3533
|
-
return true;
|
|
3534
|
-
});
|
|
3535
|
-
}
|
|
3536
|
-
function primaryUids(value) {
|
|
3537
|
-
if (!value || typeof value !== "object") return [];
|
|
3538
|
-
const object = value;
|
|
3539
|
-
const keys = [
|
|
3540
|
-
"uid",
|
|
3541
|
-
"claim_uid",
|
|
3542
|
-
"goal_uid",
|
|
3543
|
-
"project_uid",
|
|
3544
|
-
"milestone_uid",
|
|
3545
|
-
"decision_uid",
|
|
3546
|
-
"task_uid",
|
|
3547
|
-
"plan_uid",
|
|
3548
|
-
"step_uid",
|
|
3549
|
-
"execution_uid",
|
|
3550
|
-
"lesson_uid"
|
|
3551
|
-
];
|
|
3552
|
-
return [
|
|
3553
|
-
...new Set(
|
|
3554
|
-
keys.flatMap((key) => typeof object[key] === "string" ? [object[key]] : [])
|
|
3555
|
-
)
|
|
3556
|
-
];
|
|
3764
|
+
async function readGovernedResource(client2, uri, governanceConfig, memoryConfig = {}) {
|
|
3765
|
+
const toolName = uri === "mindgraph://memory/status" ? "mindgraph_memory" : RESOURCE_GOVERNANCE_TOOL;
|
|
3766
|
+
const toolArgs = uri === "mindgraph://memory/status" ? { action: "status" } : {};
|
|
3767
|
+
const governance = await checkMcpGovernance(
|
|
3768
|
+
toolName,
|
|
3769
|
+
toolArgs,
|
|
3770
|
+
{ ...governanceConfig, context: { resource_uri: uri } }
|
|
3771
|
+
);
|
|
3772
|
+
if (!governance.allowed) {
|
|
3773
|
+
throw new Error(governance.message);
|
|
3774
|
+
}
|
|
3775
|
+
return readResource(client2, uri, memoryConfig);
|
|
3557
3776
|
}
|
|
3558
3777
|
|
|
3778
|
+
// src/tools.ts
|
|
3779
|
+
var import_node_crypto6 = require("crypto");
|
|
3780
|
+
|
|
3559
3781
|
// src/sync-tool.ts
|
|
3560
3782
|
var import_node_crypto5 = __toESM(require("crypto"));
|
|
3561
|
-
var
|
|
3562
|
-
var
|
|
3783
|
+
var import_node_fs5 = __toESM(require("fs"));
|
|
3784
|
+
var import_node_path5 = __toESM(require("path"));
|
|
3563
3785
|
var ok3 = (data) => ({
|
|
3564
3786
|
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
3565
3787
|
});
|
|
@@ -3636,12 +3858,12 @@ var SYNC_TOOL = {
|
|
|
3636
3858
|
}
|
|
3637
3859
|
};
|
|
3638
3860
|
function safePath(root, candidate) {
|
|
3639
|
-
const absolute =
|
|
3640
|
-
const relative2 =
|
|
3641
|
-
if (relative2.startsWith("..") ||
|
|
3861
|
+
const absolute = import_node_path5.default.resolve(root, candidate);
|
|
3862
|
+
const relative2 = import_node_path5.default.relative(root, absolute);
|
|
3863
|
+
if (relative2.startsWith("..") || import_node_path5.default.isAbsolute(relative2)) {
|
|
3642
3864
|
throw new Error(`path escapes repository root: ${candidate}`);
|
|
3643
3865
|
}
|
|
3644
|
-
if (
|
|
3866
|
+
if (import_node_fs5.default.existsSync(absolute)) {
|
|
3645
3867
|
if (!pathContains(realPathOf(root), realPathOf(absolute))) {
|
|
3646
3868
|
throw new Error(`path escapes repository root via symlink: ${candidate}`);
|
|
3647
3869
|
}
|
|
@@ -3650,25 +3872,25 @@ function safePath(root, candidate) {
|
|
|
3650
3872
|
}
|
|
3651
3873
|
function realPathOf(target) {
|
|
3652
3874
|
try {
|
|
3653
|
-
return
|
|
3875
|
+
return import_node_fs5.default.realpathSync(target);
|
|
3654
3876
|
} catch {
|
|
3655
|
-
return
|
|
3877
|
+
return import_node_path5.default.resolve(target);
|
|
3656
3878
|
}
|
|
3657
3879
|
}
|
|
3658
3880
|
function markdownFiles(target, realRoot, visited = /* @__PURE__ */ new Set()) {
|
|
3659
|
-
if (!
|
|
3881
|
+
if (!import_node_fs5.default.existsSync(target)) return [];
|
|
3660
3882
|
const real = realPathOf(target);
|
|
3661
3883
|
if (!pathContains(realRoot, real)) return [];
|
|
3662
|
-
const stat =
|
|
3884
|
+
const stat = import_node_fs5.default.statSync(target);
|
|
3663
3885
|
if (stat.isFile()) return target.endsWith(".md") ? [target] : [];
|
|
3664
3886
|
if (!stat.isDirectory() || visited.has(real)) return [];
|
|
3665
3887
|
visited.add(real);
|
|
3666
|
-
return
|
|
3888
|
+
return import_node_fs5.default.readdirSync(target, { withFileTypes: true }).flatMap((entry) => markdownFiles(import_node_path5.default.join(target, entry.name), realRoot, visited));
|
|
3667
3889
|
}
|
|
3668
3890
|
function fileDescriptor(root, absolute) {
|
|
3669
|
-
const content =
|
|
3891
|
+
const content = import_node_fs5.default.readFileSync(absolute, "utf8");
|
|
3670
3892
|
return {
|
|
3671
|
-
logical_path:
|
|
3893
|
+
logical_path: import_node_path5.default.relative(root, absolute).split(import_node_path5.default.sep).join("/"),
|
|
3672
3894
|
content_hash: import_node_crypto5.default.createHash("sha256").update(content).digest("hex"),
|
|
3673
3895
|
bytes: Buffer.byteLength(content),
|
|
3674
3896
|
content
|
|
@@ -3738,7 +3960,7 @@ async function handleSyncTool(client2, args) {
|
|
|
3738
3960
|
}
|
|
3739
3961
|
if (action === "status" && request.logical_path && request.file_present !== false) {
|
|
3740
3962
|
const absolute = safePath(root, String(request.logical_path));
|
|
3741
|
-
request.file_present =
|
|
3963
|
+
request.file_present = import_node_fs5.default.existsSync(absolute);
|
|
3742
3964
|
if (request.file_present && !request.content_hash) {
|
|
3743
3965
|
request.content_hash = fileDescriptor(root, absolute).content_hash;
|
|
3744
3966
|
}
|
|
@@ -6270,14 +6492,14 @@ async function handleOntology(client2, args) {
|
|
|
6270
6492
|
// src/server.ts
|
|
6271
6493
|
function buildMindGraphServer(wiring) {
|
|
6272
6494
|
const { client: client2, hosted } = wiring;
|
|
6273
|
-
const
|
|
6495
|
+
const server = new import_server.Server(
|
|
6274
6496
|
{ name: "mindgraph", version: wiring.serverVersion },
|
|
6275
6497
|
{
|
|
6276
6498
|
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
6277
6499
|
instructions: wiring.instructions
|
|
6278
6500
|
}
|
|
6279
6501
|
);
|
|
6280
|
-
|
|
6502
|
+
server.setRequestHandler("tools/list", async () => {
|
|
6281
6503
|
const generated = await getGeneratedTools(client2, wiring.generatedTools);
|
|
6282
6504
|
const tools = [...toolsForProfile(wiring.profile), ...generated.tools];
|
|
6283
6505
|
if (!hosted) return { tools };
|
|
@@ -6288,7 +6510,7 @@ function buildMindGraphServer(wiring) {
|
|
|
6288
6510
|
]
|
|
6289
6511
|
};
|
|
6290
6512
|
});
|
|
6291
|
-
|
|
6513
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
6292
6514
|
const { name, arguments: args } = request.params;
|
|
6293
6515
|
const rawArgs = {
|
|
6294
6516
|
...args || {},
|
|
@@ -6335,20 +6557,20 @@ function buildMindGraphServer(wiring) {
|
|
|
6335
6557
|
}
|
|
6336
6558
|
return handleTool(client2, name, toolArgs, wiring.memory);
|
|
6337
6559
|
});
|
|
6338
|
-
|
|
6560
|
+
server.setRequestHandler("prompts/list", async () => {
|
|
6339
6561
|
return { prompts: PROMPTS };
|
|
6340
6562
|
});
|
|
6341
|
-
|
|
6563
|
+
server.setRequestHandler("prompts/get", async (request) => {
|
|
6342
6564
|
const { name, arguments: args } = request.params;
|
|
6343
6565
|
return getPrompt(name, args);
|
|
6344
6566
|
});
|
|
6345
|
-
|
|
6567
|
+
server.setRequestHandler("resources/list", async () => {
|
|
6346
6568
|
return { resources: RESOURCES };
|
|
6347
6569
|
});
|
|
6348
|
-
|
|
6570
|
+
server.setRequestHandler("resources/templates/list", async () => {
|
|
6349
6571
|
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
6350
6572
|
});
|
|
6351
|
-
|
|
6573
|
+
server.setRequestHandler("resources/read", async (request) => {
|
|
6352
6574
|
return readGovernedResource(
|
|
6353
6575
|
client2,
|
|
6354
6576
|
request.params.uri,
|
|
@@ -6356,20 +6578,20 @@ function buildMindGraphServer(wiring) {
|
|
|
6356
6578
|
wiring.memory
|
|
6357
6579
|
);
|
|
6358
6580
|
});
|
|
6359
|
-
return
|
|
6581
|
+
return server;
|
|
6360
6582
|
}
|
|
6361
6583
|
|
|
6362
6584
|
// src/index.ts
|
|
6363
|
-
var
|
|
6585
|
+
var import_node_path7 = __toESM(require("path"));
|
|
6364
6586
|
|
|
6365
6587
|
// src/hook-installer.ts
|
|
6366
|
-
var
|
|
6588
|
+
var import_node_fs6 = __toESM(require("fs"));
|
|
6367
6589
|
var import_node_os4 = __toESM(require("os"));
|
|
6368
|
-
var
|
|
6590
|
+
var import_node_path6 = __toESM(require("path"));
|
|
6369
6591
|
var import_node_crypto7 = __toESM(require("crypto"));
|
|
6370
6592
|
function storedFeatures(homeDir) {
|
|
6371
6593
|
const { promptRecall, capture } = loadHookEnv(
|
|
6372
|
-
|
|
6594
|
+
import_node_path6.default.join(homeDir || import_node_os4.default.homedir(), ".mindgraph")
|
|
6373
6595
|
);
|
|
6374
6596
|
return { promptRecall, capture };
|
|
6375
6597
|
}
|
|
@@ -6383,24 +6605,24 @@ function windowsCommand(harness) {
|
|
|
6383
6605
|
}
|
|
6384
6606
|
var RUNNER_VERSION_RELATIVE = `${RUNNER_RELATIVE}.version`;
|
|
6385
6607
|
function installHookRunner(sourceFile, homeDir, version) {
|
|
6386
|
-
const target =
|
|
6387
|
-
|
|
6608
|
+
const target = import_node_path6.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_RELATIVE);
|
|
6609
|
+
import_node_fs6.default.mkdirSync(import_node_path6.default.dirname(target), { recursive: true });
|
|
6388
6610
|
const temporary = `${target}.${process.pid}.${import_node_crypto7.default.randomUUID()}.tmp`;
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
const versionPath =
|
|
6611
|
+
import_node_fs6.default.copyFileSync(sourceFile, temporary);
|
|
6612
|
+
import_node_fs6.default.renameSync(temporary, target);
|
|
6613
|
+
const versionPath = import_node_path6.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_VERSION_RELATIVE);
|
|
6392
6614
|
if (version) {
|
|
6393
|
-
|
|
6615
|
+
import_node_fs6.default.writeFileSync(versionPath, `${version}
|
|
6394
6616
|
`);
|
|
6395
6617
|
} else {
|
|
6396
|
-
|
|
6618
|
+
import_node_fs6.default.rmSync(versionPath, { force: true });
|
|
6397
6619
|
}
|
|
6398
6620
|
return target;
|
|
6399
6621
|
}
|
|
6400
6622
|
function installedHookRunnerVersion(homeDir) {
|
|
6401
6623
|
try {
|
|
6402
|
-
const raw =
|
|
6403
|
-
|
|
6624
|
+
const raw = import_node_fs6.default.readFileSync(
|
|
6625
|
+
import_node_path6.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_VERSION_RELATIVE),
|
|
6404
6626
|
"utf8"
|
|
6405
6627
|
).trim();
|
|
6406
6628
|
return raw || void 0;
|
|
@@ -6426,21 +6648,21 @@ function refreshHookRunner(serverVersion, sourceBundle, homeDir) {
|
|
|
6426
6648
|
return { refreshed: false, reason: "disabled" };
|
|
6427
6649
|
}
|
|
6428
6650
|
const home = homeDir || import_node_os4.default.homedir();
|
|
6429
|
-
if (!
|
|
6651
|
+
if (!import_node_fs6.default.existsSync(import_node_path6.default.join(home, RUNNER_RELATIVE))) {
|
|
6430
6652
|
return { refreshed: false, reason: "no_runner" };
|
|
6431
6653
|
}
|
|
6432
|
-
if (!
|
|
6654
|
+
if (!import_node_fs6.default.existsSync(sourceBundle)) {
|
|
6433
6655
|
return { refreshed: false, reason: "no_source" };
|
|
6434
6656
|
}
|
|
6435
|
-
const
|
|
6436
|
-
if (!
|
|
6657
|
+
const server = parseSemver(serverVersion);
|
|
6658
|
+
if (!server) return { refreshed: false, reason: "unparseable" };
|
|
6437
6659
|
const runnerVersion = installedHookRunnerVersion(home);
|
|
6438
6660
|
if (runnerVersion !== void 0) {
|
|
6439
6661
|
const pinned = parseSemver(runnerVersion);
|
|
6440
6662
|
if (!pinned) {
|
|
6441
6663
|
return { refreshed: false, reason: "unparseable", runnerVersion };
|
|
6442
6664
|
}
|
|
6443
|
-
if (!semverNewer(
|
|
6665
|
+
if (!semverNewer(server, pinned)) {
|
|
6444
6666
|
return {
|
|
6445
6667
|
refreshed: false,
|
|
6446
6668
|
reason: runnerVersion === serverVersion ? "current" : "downgrade",
|
|
@@ -6460,8 +6682,8 @@ function refreshOwnedClaudeHooks(projectDir = process.cwd(), homeDir) {
|
|
|
6460
6682
|
for (const scope of scopes) {
|
|
6461
6683
|
try {
|
|
6462
6684
|
const file = settingsPath("claude-code", scope, projectDir, void 0, homeDir);
|
|
6463
|
-
if (!
|
|
6464
|
-
if (!
|
|
6685
|
+
if (!import_node_fs6.default.existsSync(file)) continue;
|
|
6686
|
+
if (!import_node_fs6.default.readFileSync(file, "utf8").includes(OWNER_MARKER)) continue;
|
|
6465
6687
|
installHooks(
|
|
6466
6688
|
"claude-code",
|
|
6467
6689
|
scope,
|
|
@@ -6481,15 +6703,15 @@ function versionSkewNote(serverVersion, homeDir) {
|
|
|
6481
6703
|
if (!runnerVersion || runnerVersion === serverVersion) return void 0;
|
|
6482
6704
|
return `NOTE: the installed MindGraph hook runner is v${runnerVersion} but this MCP server is v${serverVersion} \u2014 hook behavior and tool contracts may be out of sync. Tell the user to run: npx -y mindgraph-mcp@latest install-hooks (refreshes the pinned runner).`;
|
|
6483
6705
|
}
|
|
6484
|
-
function settingsPath(harness, scope, projectDir = process.cwd(), codexHomeDir = process.env.CODEX_HOME ||
|
|
6706
|
+
function settingsPath(harness, scope, projectDir = process.cwd(), codexHomeDir = process.env.CODEX_HOME || import_node_path6.default.join(import_node_os4.default.homedir(), ".codex"), homeDir) {
|
|
6485
6707
|
if (harness === "codex") {
|
|
6486
|
-
return scope === "user" ?
|
|
6708
|
+
return scope === "user" ? import_node_path6.default.join(codexHomeDir, "hooks.json") : import_node_path6.default.join(projectDir, ".codex", "hooks.json");
|
|
6487
6709
|
}
|
|
6488
|
-
return scope === "user" ?
|
|
6710
|
+
return scope === "user" ? import_node_path6.default.join(homeDir || import_node_os4.default.homedir(), ".claude", "settings.json") : import_node_path6.default.join(projectDir, ".claude", "settings.json");
|
|
6489
6711
|
}
|
|
6490
6712
|
function readSettings(file) {
|
|
6491
|
-
if (!
|
|
6492
|
-
return JSON.parse(
|
|
6713
|
+
if (!import_node_fs6.default.existsSync(file)) return {};
|
|
6714
|
+
return JSON.parse(import_node_fs6.default.readFileSync(file, "utf8"));
|
|
6493
6715
|
}
|
|
6494
6716
|
function ownedHook(harness, timeout, additionalContextLimit) {
|
|
6495
6717
|
return {
|
|
@@ -6578,13 +6800,13 @@ function entryHasOwnedHook(value) {
|
|
|
6578
6800
|
return Array.isArray(hooks) && hooks.some((hook) => hookCommand(hook)?.includes(OWNER_MARKER));
|
|
6579
6801
|
}
|
|
6580
6802
|
function writeSettings(file, settings) {
|
|
6581
|
-
|
|
6803
|
+
import_node_fs6.default.mkdirSync(import_node_path6.default.dirname(file), { recursive: true });
|
|
6582
6804
|
const temporary = `${file}.${process.pid}.${import_node_crypto7.default.randomUUID()}.tmp`;
|
|
6583
|
-
|
|
6805
|
+
import_node_fs6.default.writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}
|
|
6584
6806
|
`, {
|
|
6585
6807
|
mode: 384
|
|
6586
6808
|
});
|
|
6587
|
-
|
|
6809
|
+
import_node_fs6.default.renameSync(temporary, file);
|
|
6588
6810
|
}
|
|
6589
6811
|
function installHooks(harness, scope, projectDir = process.cwd(), codexHomeDir, homeDir, features = {}) {
|
|
6590
6812
|
const file = settingsPath(harness, scope, projectDir, codexHomeDir, homeDir);
|
|
@@ -6717,7 +6939,7 @@ if (PROFILE === "coding") {
|
|
|
6717
6939
|
}
|
|
6718
6940
|
var RUNNER_REFRESH = (() => {
|
|
6719
6941
|
try {
|
|
6720
|
-
return refreshHookRunner("0.
|
|
6942
|
+
return refreshHookRunner("0.26.0", import_node_path7.default.join(__dirname, "cli.js"));
|
|
6721
6943
|
} catch {
|
|
6722
6944
|
return void 0;
|
|
6723
6945
|
}
|
|
@@ -6731,12 +6953,12 @@ if (RUNNER_REFRESH?.refreshed) {
|
|
|
6731
6953
|
}
|
|
6732
6954
|
})();
|
|
6733
6955
|
console.error(
|
|
6734
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
6956
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.26.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
6735
6957
|
);
|
|
6736
6958
|
}
|
|
6737
6959
|
var HOOK_SKEW_NOTE = (() => {
|
|
6738
6960
|
try {
|
|
6739
|
-
return versionSkewNote("0.
|
|
6961
|
+
return versionSkewNote("0.26.0");
|
|
6740
6962
|
} catch {
|
|
6741
6963
|
return void 0;
|
|
6742
6964
|
}
|
|
@@ -6757,16 +6979,21 @@ var GOVERNANCE_CONFIG = {
|
|
|
6757
6979
|
}
|
|
6758
6980
|
};
|
|
6759
6981
|
var MEMORY_RUNTIME_CONFIG = {
|
|
6760
|
-
serverVersion: "0.
|
|
6982
|
+
serverVersion: "0.26.0",
|
|
6761
6983
|
baseUrl: BASE_URL,
|
|
6762
6984
|
profile: PROFILE,
|
|
6763
6985
|
harness: HARNESS,
|
|
6764
6986
|
orgId: ORG_ID,
|
|
6765
|
-
agentId: AGENT_ID
|
|
6987
|
+
agentId: AGENT_ID,
|
|
6988
|
+
resolveWorkspaceScope: (agentId) => resolveRepositoryScope(
|
|
6989
|
+
process.env.CLAUDE_PROJECT_DIR || process.cwd(),
|
|
6990
|
+
client,
|
|
6991
|
+
agentId
|
|
6992
|
+
)
|
|
6766
6993
|
};
|
|
6767
|
-
var
|
|
6994
|
+
var buildServer = () => buildMindGraphServer({
|
|
6768
6995
|
client,
|
|
6769
|
-
serverVersion: "0.
|
|
6996
|
+
serverVersion: "0.26.0",
|
|
6770
6997
|
instructions: INSTRUCTIONS,
|
|
6771
6998
|
profile: PROFILE,
|
|
6772
6999
|
agentId: AGENT_ID,
|
|
@@ -6775,10 +7002,11 @@ var server = buildMindGraphServer({
|
|
|
6775
7002
|
resolveHookFields: (name, args) => resolvePendingCall(name, args)
|
|
6776
7003
|
});
|
|
6777
7004
|
async function main() {
|
|
6778
|
-
|
|
6779
|
-
|
|
7005
|
+
(0, import_stdio.serveStdio)(buildServer, {
|
|
7006
|
+
onerror: (error2) => console.error("MindGraph MCP transport error:", error2.message)
|
|
7007
|
+
});
|
|
6780
7008
|
console.error(
|
|
6781
|
-
`MindGraph MCP server v${"0.
|
|
7009
|
+
`MindGraph MCP server v${"0.26.0"} running on stdio (${BASE_URL})`
|
|
6782
7010
|
);
|
|
6783
7011
|
}
|
|
6784
7012
|
main().catch((error2) => {
|