mindgraph-mcp 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/cli.js +467 -208
- package/dist/index.js +244 -148
- package/dist/server.d.mts +8 -3
- package/dist/server.d.ts +8 -3
- package/dist/server.js +54 -13
- package/dist/server.mjs +57 -19
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -22,30 +22,85 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
// src/
|
|
26
|
-
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
27
|
-
var import_mindgraph3 = require("mindgraph");
|
|
28
|
-
|
|
29
|
-
// src/hook-env.ts
|
|
25
|
+
// src/call-ledger.ts
|
|
30
26
|
var import_node_crypto = __toESM(require("crypto"));
|
|
31
27
|
var import_node_fs = __toESM(require("fs"));
|
|
32
28
|
var import_node_os = __toESM(require("os"));
|
|
33
29
|
var import_node_path = __toESM(require("path"));
|
|
30
|
+
var TTL_MS = 10 * 6e4;
|
|
31
|
+
function callsDir(options) {
|
|
32
|
+
return import_node_path.default.join(
|
|
33
|
+
options.runtimeDir || process.env.MINDGRAPH_RUNTIME_DIR || import_node_path.default.join(import_node_os.default.homedir(), ".mindgraph", "runtime"),
|
|
34
|
+
"calls"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function stableJson(value) {
|
|
38
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
39
|
+
if (value && typeof value === "object") {
|
|
40
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
41
|
+
}
|
|
42
|
+
return JSON.stringify(value) ?? "null";
|
|
43
|
+
}
|
|
44
|
+
function bareToolName(name) {
|
|
45
|
+
const cut = name.lastIndexOf("__");
|
|
46
|
+
return cut === -1 ? name : name.slice(cut + 2);
|
|
47
|
+
}
|
|
48
|
+
function callKey(toolName, toolInput) {
|
|
49
|
+
return import_node_crypto.default.createHash("sha256").update(`${bareToolName(toolName)}\0${stableJson(toolInput)}`).digest("hex");
|
|
50
|
+
}
|
|
51
|
+
function resolvePendingCall(toolName, toolInput, options = {}) {
|
|
52
|
+
const now = (options.now ?? Date.now)();
|
|
53
|
+
const dir = callsDir(options);
|
|
54
|
+
const prefix = `${callKey(toolName, toolInput)}.`;
|
|
55
|
+
let names;
|
|
56
|
+
try {
|
|
57
|
+
names = import_node_fs.default.readdirSync(dir).filter((name) => name.startsWith(prefix) && name.endsWith(".json"));
|
|
58
|
+
} catch {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
let matches = [];
|
|
62
|
+
for (const name of names) {
|
|
63
|
+
try {
|
|
64
|
+
const record = JSON.parse(
|
|
65
|
+
import_node_fs.default.readFileSync(import_node_path.default.join(dir, name), "utf8")
|
|
66
|
+
);
|
|
67
|
+
if (typeof record.createdAt === "number" && now - record.createdAt <= TTL_MS && record.fills && typeof record.fills === "object") {
|
|
68
|
+
matches.push(record);
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (matches.length > 1) {
|
|
74
|
+
const projectDir = options.projectDir ?? process.env.CLAUDE_PROJECT_DIR;
|
|
75
|
+
matches = projectDir ? matches.filter((record) => record.projectDir === projectDir) : [];
|
|
76
|
+
}
|
|
77
|
+
return matches.length === 1 ? matches[0].fills : void 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/index.ts
|
|
81
|
+
var import_stdio = require("@modelcontextprotocol/server/stdio");
|
|
82
|
+
var import_mindgraph3 = require("mindgraph");
|
|
83
|
+
|
|
84
|
+
// src/hook-env.ts
|
|
85
|
+
var import_node_crypto2 = __toESM(require("crypto"));
|
|
86
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
87
|
+
var import_node_os2 = __toESM(require("os"));
|
|
88
|
+
var import_node_path2 = __toESM(require("path"));
|
|
34
89
|
function stableAgentId() {
|
|
35
90
|
let user = "user";
|
|
36
91
|
try {
|
|
37
|
-
user =
|
|
92
|
+
user = import_node_os2.default.userInfo().username || "user";
|
|
38
93
|
} catch {
|
|
39
94
|
}
|
|
40
|
-
const digest =
|
|
95
|
+
const digest = import_node_crypto2.default.createHash("sha256").update(`${user}@${import_node_os2.default.hostname()}`).digest("hex").slice(0, 12);
|
|
41
96
|
return `u-${digest}`;
|
|
42
97
|
}
|
|
43
98
|
function hookEnvPath(dir) {
|
|
44
|
-
return
|
|
99
|
+
return import_node_path2.default.join(dir || import_node_path2.default.join(import_node_os2.default.homedir(), ".mindgraph"), "hooks.json");
|
|
45
100
|
}
|
|
46
101
|
function loadHookEnv(dir) {
|
|
47
102
|
try {
|
|
48
|
-
const raw =
|
|
103
|
+
const raw = import_node_fs2.default.readFileSync(hookEnvPath(dir), "utf8");
|
|
49
104
|
const parsed = JSON.parse(raw);
|
|
50
105
|
return {
|
|
51
106
|
baseUrl: typeof parsed.baseUrl === "string" ? parsed.baseUrl : void 0,
|
|
@@ -61,9 +116,7 @@ function loadHookEnv(dir) {
|
|
|
61
116
|
}
|
|
62
117
|
|
|
63
118
|
// src/server.ts
|
|
64
|
-
var import_server = require("@modelcontextprotocol/
|
|
65
|
-
var import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
|
|
66
|
-
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
119
|
+
var import_server = require("@modelcontextprotocol/server");
|
|
67
120
|
|
|
68
121
|
// src/error-detail.ts
|
|
69
122
|
var import_mindgraph = require("mindgraph");
|
|
@@ -357,6 +410,14 @@ function hiddenSections(payload) {
|
|
|
357
410
|
function renderContext(response, maxChars) {
|
|
358
411
|
const payload = obj(response);
|
|
359
412
|
if (!payload) return void 0;
|
|
413
|
+
if (typeof payload.context_text === "string" && payload.context_text.length > 0) {
|
|
414
|
+
const text2 = payload.context_text;
|
|
415
|
+
if (maxChars !== void 0 && text2.length > maxChars) {
|
|
416
|
+
return `${text2.slice(0, maxChars)}
|
|
417
|
+
[truncated to ${maxChars} characters]`;
|
|
418
|
+
}
|
|
419
|
+
return text2;
|
|
420
|
+
}
|
|
360
421
|
const graph = obj(payload.graph);
|
|
361
422
|
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
362
423
|
const shaped = rawNodes.filter(isNodeShaped);
|
|
@@ -579,15 +640,15 @@ function renderTraversal(response, maxChars) {
|
|
|
579
640
|
const labelByUid = /* @__PURE__ */ new Map();
|
|
580
641
|
for (const node of nodes) labelByUid.set(str(node.uid), str(node.label) || "?");
|
|
581
642
|
if (paths.length > 0) {
|
|
582
|
-
const items = paths.map((raw) => obj(raw)).filter((
|
|
583
|
-
const uids = Array.isArray(
|
|
584
|
-
const labels = Array.isArray(
|
|
643
|
+
const items = paths.map((raw) => obj(raw)).filter((path6) => Boolean(path6)).map((path6, index) => {
|
|
644
|
+
const uids = Array.isArray(path6.node_uids) ? path6.node_uids.map(String) : [];
|
|
645
|
+
const labels = Array.isArray(path6.labels) ? path6.labels.map(String) : Array.isArray(path6.nodes) ? path6.nodes.map((hop) => {
|
|
585
646
|
const hopNode = obj(hop);
|
|
586
647
|
return str(hopNode?.label) || labelByUid.get(str(hopNode?.uid) || "") || str(hop) || "?";
|
|
587
648
|
}) : [];
|
|
588
649
|
const route = labels.length > 0 ? labels.join(" \u2192 ") : uids.join(" \u2192 ") || "(path)";
|
|
589
|
-
const cost = num(
|
|
590
|
-
const confidence = num(
|
|
650
|
+
const cost = num(path6.cost) ?? num(path6.path_cost);
|
|
651
|
+
const confidence = num(path6.path_confidence);
|
|
591
652
|
const meta = [
|
|
592
653
|
cost !== void 0 ? `cost ${cost}` : void 0,
|
|
593
654
|
confidence !== void 0 ? `confidence ${confidence}` : void 0
|
|
@@ -1589,7 +1650,7 @@ ${conversation}`
|
|
|
1589
1650
|
}
|
|
1590
1651
|
|
|
1591
1652
|
// src/memory-tool.ts
|
|
1592
|
-
var
|
|
1653
|
+
var import_node_crypto3 = require("crypto");
|
|
1593
1654
|
var RESULT_SCHEMA_VERSION = "mindgraph.memory.result.v1";
|
|
1594
1655
|
var DEFAULT_OUTPUT_CHARS = 8e3;
|
|
1595
1656
|
var MIN_OUTPUT_CHARS = 512;
|
|
@@ -1737,15 +1798,15 @@ function obj2(value) {
|
|
|
1737
1798
|
function text(value) {
|
|
1738
1799
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1739
1800
|
}
|
|
1740
|
-
function
|
|
1741
|
-
if (Array.isArray(value)) return `[${value.map(
|
|
1801
|
+
function stableJson2(value) {
|
|
1802
|
+
if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
|
|
1742
1803
|
if (value && typeof value === "object") {
|
|
1743
|
-
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${
|
|
1804
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson2(item)}`).join(",")}}`;
|
|
1744
1805
|
}
|
|
1745
1806
|
return JSON.stringify(value);
|
|
1746
1807
|
}
|
|
1747
1808
|
function sha256(value) {
|
|
1748
|
-
return (0,
|
|
1809
|
+
return (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
|
|
1749
1810
|
}
|
|
1750
1811
|
function outputBudget(value) {
|
|
1751
1812
|
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_OUTPUT_CHARS;
|
|
@@ -2051,7 +2112,7 @@ async function handleMemoryTool(client2, args, config = {}) {
|
|
|
2051
2112
|
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0
|
|
2052
2113
|
});
|
|
2053
2114
|
const contextId = `ctx_${sha256(
|
|
2054
|
-
|
|
2115
|
+
stableJson2({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
2055
2116
|
).slice(0, 24)}`;
|
|
2056
2117
|
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
2057
2118
|
const result = {
|
|
@@ -2212,15 +2273,15 @@ async function readGovernedResource(client2, uri, governanceConfig, memoryConfig
|
|
|
2212
2273
|
}
|
|
2213
2274
|
|
|
2214
2275
|
// src/tools.ts
|
|
2215
|
-
var
|
|
2276
|
+
var import_node_crypto6 = require("crypto");
|
|
2216
2277
|
|
|
2217
2278
|
// src/codegraph.ts
|
|
2218
2279
|
var import_node_child_process = require("child_process");
|
|
2219
|
-
var
|
|
2280
|
+
var import_node_fs3 = require("fs");
|
|
2220
2281
|
var import_promises = require("fs/promises");
|
|
2221
|
-
var
|
|
2222
|
-
var
|
|
2223
|
-
var
|
|
2282
|
+
var import_node_os3 = require("os");
|
|
2283
|
+
var import_node_path3 = require("path");
|
|
2284
|
+
var import_node_crypto4 = require("crypto");
|
|
2224
2285
|
var UnknownRepositoryError = class extends Error {
|
|
2225
2286
|
constructor(repo) {
|
|
2226
2287
|
super(
|
|
@@ -2251,14 +2312,14 @@ function unavailabilityCaveats(reason, message) {
|
|
|
2251
2312
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
2252
2313
|
var DEFAULT_STATUS_TTL_MS = 6e4;
|
|
2253
2314
|
var MAX_OUTPUT_BYTES = 5 * 1024 * 1024;
|
|
2254
|
-
function normalizePath(
|
|
2255
|
-
return
|
|
2315
|
+
function normalizePath(path6) {
|
|
2316
|
+
return path6.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
2256
2317
|
}
|
|
2257
2318
|
function normalizeSignature(signature) {
|
|
2258
2319
|
return signature.replace(/\s+/g, " ").trim();
|
|
2259
2320
|
}
|
|
2260
|
-
function languageFromPath(
|
|
2261
|
-
const extension = (0,
|
|
2321
|
+
function languageFromPath(path6) {
|
|
2322
|
+
const extension = (0, import_node_path3.extname)(path6).toLowerCase();
|
|
2262
2323
|
return {
|
|
2263
2324
|
".c": "c",
|
|
2264
2325
|
".cc": "cpp",
|
|
@@ -2307,30 +2368,30 @@ function normalizeRemote(remote) {
|
|
|
2307
2368
|
}
|
|
2308
2369
|
}
|
|
2309
2370
|
function pathContains(root, candidate) {
|
|
2310
|
-
const child = (0,
|
|
2311
|
-
return child === "" || child !== ".." && !child.startsWith(`..${
|
|
2371
|
+
const child = (0, import_node_path3.relative)(root, candidate);
|
|
2372
|
+
return child === "" || child !== ".." && !child.startsWith(`..${import_node_path3.sep}`) && !(0, import_node_path3.isAbsolute)(child);
|
|
2312
2373
|
}
|
|
2313
2374
|
function nearestExistingDirectory(candidate) {
|
|
2314
|
-
let current = (0,
|
|
2375
|
+
let current = (0, import_node_path3.resolve)(candidate);
|
|
2315
2376
|
for (; ; ) {
|
|
2316
|
-
if ((0,
|
|
2377
|
+
if ((0, import_node_fs3.existsSync)(current)) {
|
|
2317
2378
|
try {
|
|
2318
|
-
return (0,
|
|
2379
|
+
return (0, import_node_fs3.statSync)(current).isDirectory() ? current : (0, import_node_path3.dirname)(current);
|
|
2319
2380
|
} catch {
|
|
2320
2381
|
}
|
|
2321
2382
|
}
|
|
2322
|
-
const parent = (0,
|
|
2383
|
+
const parent = (0, import_node_path3.dirname)(current);
|
|
2323
2384
|
if (parent === current) return current;
|
|
2324
2385
|
current = parent;
|
|
2325
2386
|
}
|
|
2326
2387
|
}
|
|
2327
2388
|
function findWorkspaceFile(start, explicit) {
|
|
2328
|
-
if (explicit) return (0,
|
|
2329
|
-
let current = (0,
|
|
2389
|
+
if (explicit) return (0, import_node_path3.resolve)(start, explicit);
|
|
2390
|
+
let current = (0, import_node_path3.resolve)(start);
|
|
2330
2391
|
for (; ; ) {
|
|
2331
|
-
const candidate = (0,
|
|
2332
|
-
if ((0,
|
|
2333
|
-
const parent = (0,
|
|
2392
|
+
const candidate = (0, import_node_path3.join)(current, ".mindgraph", "workspace.json");
|
|
2393
|
+
if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
|
|
2394
|
+
const parent = (0, import_node_path3.dirname)(current);
|
|
2334
2395
|
if (parent === current) return void 0;
|
|
2335
2396
|
current = parent;
|
|
2336
2397
|
}
|
|
@@ -2417,7 +2478,7 @@ var CodegraphAdapter = class {
|
|
|
2417
2478
|
async resolveRepository(repo, fallbackSpaceUid) {
|
|
2418
2479
|
const configured = await this.resolveRepositories(fallbackSpaceUid);
|
|
2419
2480
|
const selected = repo && configured.find((candidate) => candidate.repoId === repo) || repo && configured.find(
|
|
2420
|
-
(candidate) => candidate.repoRoot === repo || (0,
|
|
2481
|
+
(candidate) => candidate.repoRoot === repo || (0, import_node_path3.basename)(candidate.repoRoot) === repo
|
|
2421
2482
|
) || (!repo ? [...configured].sort((a, b) => b.repoRoot.length - a.repoRoot.length).find((candidate) => pathContains(candidate.repoRoot, this.cwd)) : void 0) || (!repo && configured.length === 1 ? configured[0] : void 0);
|
|
2422
2483
|
if (selected) {
|
|
2423
2484
|
return !repo && this.env.MINDGRAPH_REPO_ID ? this.resolveRepositoryIdentity(
|
|
@@ -2427,10 +2488,10 @@ var CodegraphAdapter = class {
|
|
|
2427
2488
|
) : selected;
|
|
2428
2489
|
}
|
|
2429
2490
|
if (repo) {
|
|
2430
|
-
const requestedPath = await (0, import_promises.realpath)((0,
|
|
2431
|
-
() => (0,
|
|
2491
|
+
const requestedPath = await (0, import_promises.realpath)((0, import_node_path3.resolve)(this.cwd, repo)).catch(
|
|
2492
|
+
() => (0, import_node_path3.resolve)(this.cwd, repo)
|
|
2432
2493
|
);
|
|
2433
|
-
if (!(0,
|
|
2494
|
+
if (!(0, import_node_fs3.existsSync)(requestedPath)) {
|
|
2434
2495
|
const current = await this.currentRepository(fallbackSpaceUid);
|
|
2435
2496
|
if (current.repoId === repo) return current;
|
|
2436
2497
|
throw new UnknownRepositoryError(repo);
|
|
@@ -2446,8 +2507,8 @@ var CodegraphAdapter = class {
|
|
|
2446
2507
|
}
|
|
2447
2508
|
async currentRepository(fallbackSpaceUid) {
|
|
2448
2509
|
const requestedRoot = this.env.MINDGRAPH_REPO_ROOT || this.cwd;
|
|
2449
|
-
const requestedPath = await (0, import_promises.realpath)((0,
|
|
2450
|
-
() => (0,
|
|
2510
|
+
const requestedPath = await (0, import_promises.realpath)((0, import_node_path3.resolve)(this.cwd, requestedRoot)).catch(
|
|
2511
|
+
() => (0, import_node_path3.resolve)(this.cwd, requestedRoot)
|
|
2451
2512
|
);
|
|
2452
2513
|
const repoRoot = await this.gitRoot(requestedPath) ?? requestedPath;
|
|
2453
2514
|
return this.resolveRepositoryIdentity(
|
|
@@ -2468,7 +2529,7 @@ var CodegraphAdapter = class {
|
|
|
2468
2529
|
);
|
|
2469
2530
|
}
|
|
2470
2531
|
async resolveRepositoryIdentity(root, explicitRepoId, spaceUid) {
|
|
2471
|
-
const repoRoot = await (0, import_promises.realpath)(root).catch(() => (0,
|
|
2532
|
+
const repoRoot = await (0, import_promises.realpath)(root).catch(() => (0, import_node_path3.resolve)(root));
|
|
2472
2533
|
const cacheKey = `${repoRoot}\0${explicitRepoId ?? ""}\0${spaceUid ?? ""}`;
|
|
2473
2534
|
const cached = this.identityCache.get(cacheKey);
|
|
2474
2535
|
if (cached) return cached;
|
|
@@ -2498,20 +2559,20 @@ var CodegraphAdapter = class {
|
|
|
2498
2559
|
this.env
|
|
2499
2560
|
).catch(() => "");
|
|
2500
2561
|
if (!rawCommonDir.trim()) {
|
|
2501
|
-
return `local:${(0,
|
|
2562
|
+
return `local:${(0, import_node_path3.basename)(repoRoot)}`;
|
|
2502
2563
|
}
|
|
2503
|
-
const commonDir = (0,
|
|
2504
|
-
const identityDir = (0,
|
|
2505
|
-
const identityFile = (0,
|
|
2564
|
+
const commonDir = (0, import_node_path3.resolve)(repoRoot, rawCommonDir.trim());
|
|
2565
|
+
const identityDir = (0, import_node_path3.join)(commonDir, "mindgraph");
|
|
2566
|
+
const identityFile = (0, import_node_path3.join)(identityDir, "repository-id");
|
|
2506
2567
|
try {
|
|
2507
|
-
const existing = (0,
|
|
2568
|
+
const existing = (0, import_node_fs3.readFileSync)(identityFile, "utf8").trim();
|
|
2508
2569
|
if (existing) return existing;
|
|
2509
2570
|
} catch {
|
|
2510
2571
|
}
|
|
2511
|
-
(0,
|
|
2512
|
-
const generated = (0,
|
|
2572
|
+
(0, import_node_fs3.mkdirSync)(identityDir, { recursive: true, mode: 448 });
|
|
2573
|
+
const generated = (0, import_node_crypto4.randomUUID)();
|
|
2513
2574
|
try {
|
|
2514
|
-
(0,
|
|
2575
|
+
(0, import_node_fs3.writeFileSync)(identityFile, `${generated}
|
|
2515
2576
|
`, {
|
|
2516
2577
|
encoding: "utf8",
|
|
2517
2578
|
flag: "wx",
|
|
@@ -2520,7 +2581,7 @@ var CodegraphAdapter = class {
|
|
|
2520
2581
|
return generated;
|
|
2521
2582
|
} catch (cause) {
|
|
2522
2583
|
if (cause.code !== "EEXIST") throw cause;
|
|
2523
|
-
const winner = (0,
|
|
2584
|
+
const winner = (0, import_node_fs3.readFileSync)(identityFile, "utf8").trim();
|
|
2524
2585
|
if (!winner) throw new Error(`empty repository identity file: ${identityFile}`);
|
|
2525
2586
|
return winner;
|
|
2526
2587
|
}
|
|
@@ -2533,12 +2594,12 @@ var CodegraphAdapter = class {
|
|
|
2533
2594
|
Math.min(this.timeoutMs, 2e3),
|
|
2534
2595
|
this.env
|
|
2535
2596
|
).catch(() => "");
|
|
2536
|
-
return raw.trim() ? (0,
|
|
2597
|
+
return raw.trim() ? (0, import_node_path3.resolve)(start, raw.trim()) : void 0;
|
|
2537
2598
|
}
|
|
2538
2599
|
/** Why the workspace map yielded no repositories — for callers that were
|
|
2539
2600
|
* explicitly asked to fan out and would otherwise return silently empty. */
|
|
2540
2601
|
workspaceDiagnostic() {
|
|
2541
|
-
if (!this.workspaceFile || !(0,
|
|
2602
|
+
if (!this.workspaceFile || !(0, import_node_fs3.existsSync)(this.workspaceFile)) {
|
|
2542
2603
|
return "no .mindgraph/workspace.json was found between the working directory and the filesystem root";
|
|
2543
2604
|
}
|
|
2544
2605
|
return `${this.workspaceFile} is malformed or declares no repositories`;
|
|
@@ -2658,7 +2719,7 @@ var CodegraphAdapter = class {
|
|
|
2658
2719
|
return this.resolveRepository(ref.repo || defaultRepo, fallbackSpaceUid);
|
|
2659
2720
|
}
|
|
2660
2721
|
if (ref.path) {
|
|
2661
|
-
const requested = (0,
|
|
2722
|
+
const requested = (0, import_node_path3.isAbsolute)(ref.path) ? (0, import_node_path3.resolve)(ref.path) : (0, import_node_path3.resolve)(this.cwd, ref.path);
|
|
2662
2723
|
const absolute = await (0, import_promises.realpath)(requested).catch(() => requested);
|
|
2663
2724
|
const configured = await this.resolveRepositories(fallbackSpaceUid);
|
|
2664
2725
|
const defining = [...configured].sort((a, b) => b.repoRoot.length - a.repoRoot.length).find((candidate) => pathContains(candidate.repoRoot, absolute));
|
|
@@ -2735,19 +2796,19 @@ var CodegraphAdapter = class {
|
|
|
2735
2796
|
}
|
|
2736
2797
|
configuredRepositories() {
|
|
2737
2798
|
const configured = [];
|
|
2738
|
-
if (this.workspaceFile && (0,
|
|
2799
|
+
if (this.workspaceFile && (0, import_node_fs3.existsSync)(this.workspaceFile)) {
|
|
2739
2800
|
try {
|
|
2740
2801
|
const parsed = JSON.parse(
|
|
2741
|
-
(0,
|
|
2802
|
+
(0, import_node_fs3.readFileSync)(this.workspaceFile, "utf8")
|
|
2742
2803
|
);
|
|
2743
2804
|
if (parsed.v === 1 && Array.isArray(parsed.repositories)) {
|
|
2744
|
-
const configDirectory = (0,
|
|
2745
|
-
const base = (0,
|
|
2805
|
+
const configDirectory = (0, import_node_path3.dirname)(this.workspaceFile);
|
|
2806
|
+
const base = (0, import_node_path3.basename)(configDirectory) === ".mindgraph" ? (0, import_node_path3.dirname)(configDirectory) : configDirectory;
|
|
2746
2807
|
for (const repository of parsed.repositories) {
|
|
2747
2808
|
if (!repository || typeof repository.root !== "string") continue;
|
|
2748
2809
|
configured.push({
|
|
2749
2810
|
repoId: typeof repository.repo_id === "string" ? repository.repo_id : void 0,
|
|
2750
|
-
repoRoot: (0,
|
|
2811
|
+
repoRoot: (0, import_node_path3.resolve)(base, repository.root),
|
|
2751
2812
|
spaceUid: typeof repository.space_uid === "string" ? repository.space_uid : void 0
|
|
2752
2813
|
});
|
|
2753
2814
|
}
|
|
@@ -2762,7 +2823,7 @@ var CodegraphAdapter = class {
|
|
|
2762
2823
|
for (const [repoId, config] of Object.entries(parsed)) {
|
|
2763
2824
|
configured.push({
|
|
2764
2825
|
repoId,
|
|
2765
|
-
repoRoot: (0,
|
|
2826
|
+
repoRoot: (0, import_node_path3.resolve)(
|
|
2766
2827
|
this.cwd,
|
|
2767
2828
|
typeof config === "string" ? config : config.root
|
|
2768
2829
|
),
|
|
@@ -2790,9 +2851,9 @@ var CodegraphAdapter = class {
|
|
|
2790
2851
|
const hits = await this.runJson(args);
|
|
2791
2852
|
let candidates = hits.map(asNode).map(toCandidate).filter((item) => item !== null);
|
|
2792
2853
|
if (ref.path) {
|
|
2793
|
-
const absolutePath = (0,
|
|
2854
|
+
const absolutePath = (0, import_node_path3.isAbsolute)(ref.path) ? await (0, import_promises.realpath)(ref.path).catch(() => ref.path) : void 0;
|
|
2794
2855
|
const wanted = normalizePath(
|
|
2795
|
-
absolutePath ? (0,
|
|
2856
|
+
absolutePath ? (0, import_node_path3.relative)(repository.repoRoot, absolutePath) : ref.path
|
|
2796
2857
|
);
|
|
2797
2858
|
candidates = candidates.filter((candidate) => candidate.path === wanted);
|
|
2798
2859
|
}
|
|
@@ -2893,7 +2954,7 @@ var CodegraphAdapter = class {
|
|
|
2893
2954
|
const candidates = [
|
|
2894
2955
|
this.env.MINDGRAPH_CODEGRAPH_BIN,
|
|
2895
2956
|
"codegraph",
|
|
2896
|
-
(0,
|
|
2957
|
+
(0, import_node_path3.resolve)((0, import_node_os3.homedir)(), ".local", "bin", "codegraph")
|
|
2897
2958
|
].filter((candidate, index, all) => {
|
|
2898
2959
|
return Boolean(candidate) && all.indexOf(candidate) === index;
|
|
2899
2960
|
});
|
|
@@ -3494,9 +3555,9 @@ function primaryUids(value) {
|
|
|
3494
3555
|
}
|
|
3495
3556
|
|
|
3496
3557
|
// src/sync-tool.ts
|
|
3497
|
-
var
|
|
3498
|
-
var
|
|
3499
|
-
var
|
|
3558
|
+
var import_node_crypto5 = __toESM(require("crypto"));
|
|
3559
|
+
var import_node_fs4 = __toESM(require("fs"));
|
|
3560
|
+
var import_node_path4 = __toESM(require("path"));
|
|
3500
3561
|
var ok3 = (data) => ({
|
|
3501
3562
|
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
3502
3563
|
});
|
|
@@ -3573,12 +3634,12 @@ var SYNC_TOOL = {
|
|
|
3573
3634
|
}
|
|
3574
3635
|
};
|
|
3575
3636
|
function safePath(root, candidate) {
|
|
3576
|
-
const absolute =
|
|
3577
|
-
const relative2 =
|
|
3578
|
-
if (relative2.startsWith("..") ||
|
|
3637
|
+
const absolute = import_node_path4.default.resolve(root, candidate);
|
|
3638
|
+
const relative2 = import_node_path4.default.relative(root, absolute);
|
|
3639
|
+
if (relative2.startsWith("..") || import_node_path4.default.isAbsolute(relative2)) {
|
|
3579
3640
|
throw new Error(`path escapes repository root: ${candidate}`);
|
|
3580
3641
|
}
|
|
3581
|
-
if (
|
|
3642
|
+
if (import_node_fs4.default.existsSync(absolute)) {
|
|
3582
3643
|
if (!pathContains(realPathOf(root), realPathOf(absolute))) {
|
|
3583
3644
|
throw new Error(`path escapes repository root via symlink: ${candidate}`);
|
|
3584
3645
|
}
|
|
@@ -3587,26 +3648,26 @@ function safePath(root, candidate) {
|
|
|
3587
3648
|
}
|
|
3588
3649
|
function realPathOf(target) {
|
|
3589
3650
|
try {
|
|
3590
|
-
return
|
|
3651
|
+
return import_node_fs4.default.realpathSync(target);
|
|
3591
3652
|
} catch {
|
|
3592
|
-
return
|
|
3653
|
+
return import_node_path4.default.resolve(target);
|
|
3593
3654
|
}
|
|
3594
3655
|
}
|
|
3595
3656
|
function markdownFiles(target, realRoot, visited = /* @__PURE__ */ new Set()) {
|
|
3596
|
-
if (!
|
|
3657
|
+
if (!import_node_fs4.default.existsSync(target)) return [];
|
|
3597
3658
|
const real = realPathOf(target);
|
|
3598
3659
|
if (!pathContains(realRoot, real)) return [];
|
|
3599
|
-
const stat =
|
|
3660
|
+
const stat = import_node_fs4.default.statSync(target);
|
|
3600
3661
|
if (stat.isFile()) return target.endsWith(".md") ? [target] : [];
|
|
3601
3662
|
if (!stat.isDirectory() || visited.has(real)) return [];
|
|
3602
3663
|
visited.add(real);
|
|
3603
|
-
return
|
|
3664
|
+
return import_node_fs4.default.readdirSync(target, { withFileTypes: true }).flatMap((entry) => markdownFiles(import_node_path4.default.join(target, entry.name), realRoot, visited));
|
|
3604
3665
|
}
|
|
3605
3666
|
function fileDescriptor(root, absolute) {
|
|
3606
|
-
const content =
|
|
3667
|
+
const content = import_node_fs4.default.readFileSync(absolute, "utf8");
|
|
3607
3668
|
return {
|
|
3608
|
-
logical_path:
|
|
3609
|
-
content_hash:
|
|
3669
|
+
logical_path: import_node_path4.default.relative(root, absolute).split(import_node_path4.default.sep).join("/"),
|
|
3670
|
+
content_hash: import_node_crypto5.default.createHash("sha256").update(content).digest("hex"),
|
|
3610
3671
|
bytes: Buffer.byteLength(content),
|
|
3611
3672
|
content
|
|
3612
3673
|
};
|
|
@@ -3675,7 +3736,7 @@ async function handleSyncTool(client2, args) {
|
|
|
3675
3736
|
}
|
|
3676
3737
|
if (action === "status" && request.logical_path && request.file_present !== false) {
|
|
3677
3738
|
const absolute = safePath(root, String(request.logical_path));
|
|
3678
|
-
request.file_present =
|
|
3739
|
+
request.file_present = import_node_fs4.default.existsSync(absolute);
|
|
3679
3740
|
if (request.file_present && !request.content_hash) {
|
|
3680
3741
|
request.content_hash = fileDescriptor(root, absolute).content_hash;
|
|
3681
3742
|
}
|
|
@@ -3748,10 +3809,10 @@ var RESOLUTION_PROPERTIES = {
|
|
|
3748
3809
|
description: "Alias for confirm_new on a near-duplicate response"
|
|
3749
3810
|
}
|
|
3750
3811
|
};
|
|
3751
|
-
function
|
|
3752
|
-
if (Array.isArray(value)) return `[${value.map(
|
|
3812
|
+
function stableJson3(value) {
|
|
3813
|
+
if (Array.isArray(value)) return `[${value.map(stableJson3).join(",")}]`;
|
|
3753
3814
|
if (value && typeof value === "object") {
|
|
3754
|
-
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${
|
|
3815
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson3(item)}`).join(",")}}`;
|
|
3755
3816
|
}
|
|
3756
3817
|
return JSON.stringify(value);
|
|
3757
3818
|
}
|
|
@@ -3765,8 +3826,8 @@ function defaultWriteIdempotencyKey(tool, args) {
|
|
|
3765
3826
|
([key]) => key !== "invocation_context" && key !== "idempotency_key"
|
|
3766
3827
|
)
|
|
3767
3828
|
);
|
|
3768
|
-
return (0,
|
|
3769
|
-
|
|
3829
|
+
return (0, import_node_crypto6.createHash)("sha256").update(
|
|
3830
|
+
stableJson3({
|
|
3770
3831
|
harness_session_id: sessionId,
|
|
3771
3832
|
harness_turn_id: context?.harnessTurnId ?? null,
|
|
3772
3833
|
tool,
|
|
@@ -4478,6 +4539,15 @@ var TOOLS = [
|
|
|
4478
4539
|
type: "string",
|
|
4479
4540
|
description: "ISO-8601 date (e.g. '2021-06') for context: nodes with validity windows are annotated as of this date instead of today"
|
|
4480
4541
|
},
|
|
4542
|
+
as_of: {
|
|
4543
|
+
type: "string",
|
|
4544
|
+
description: "ISO-8601 date for context: answer with what had been STATED by this date (a node is admitted when one of its sources was stated on or before it; fact dates never exclude it). Use for 'what did we know / what was the value as of <date>' questions."
|
|
4545
|
+
},
|
|
4546
|
+
retrieval_mode: {
|
|
4547
|
+
type: "string",
|
|
4548
|
+
enum: ["normal", "exhaustive"],
|
|
4549
|
+
description: "context: 'exhaustive' widens retrieval for list/count questions ('how many different \u2026 across', 'what two \u2026'); omitted lets the server's cue decide."
|
|
4550
|
+
},
|
|
4481
4551
|
created_after: {
|
|
4482
4552
|
type: "number",
|
|
4483
4553
|
description: "Unix seconds \u2014 'recent' action: only nodes ingested after this time"
|
|
@@ -5706,6 +5776,8 @@ async function handleRetrieve(client2, args, profile) {
|
|
|
5706
5776
|
salience_min,
|
|
5707
5777
|
article_limit,
|
|
5708
5778
|
valid_at,
|
|
5779
|
+
as_of,
|
|
5780
|
+
retrieval_mode,
|
|
5709
5781
|
created_after,
|
|
5710
5782
|
created_before,
|
|
5711
5783
|
explain,
|
|
@@ -5734,9 +5806,15 @@ async function handleRetrieve(client2, args, profile) {
|
|
|
5734
5806
|
// the advertised knob must not get a silent no-op).
|
|
5735
5807
|
...article_limit !== void 0 ? { article_limit } : include_documents === false || profile === "coding" && !include_documents ? { article_limit: 0 } : {},
|
|
5736
5808
|
valid_at,
|
|
5809
|
+
as_of,
|
|
5810
|
+
retrieval_mode,
|
|
5737
5811
|
include_graph,
|
|
5738
5812
|
graph_expansion_limit: graph_expansion_limit ?? 3,
|
|
5739
|
-
graph_max_depth: graph_max_depth ?? 2
|
|
5813
|
+
graph_max_depth: graph_max_depth ?? 2,
|
|
5814
|
+
// Evidence plan R2: the server's canonical rendering under a token
|
|
5815
|
+
// budget derived from the character budget; the local renderer is
|
|
5816
|
+
// the fallback for servers that predate it.
|
|
5817
|
+
...format === "json" ? {} : { format: "text", max_tokens: Math.max(256, Math.floor((max_output_chars ?? 24e3) / 4)) }
|
|
5740
5818
|
}),
|
|
5741
5819
|
(raw) => renderContext(raw, max_output_chars)
|
|
5742
5820
|
);
|
|
@@ -6190,14 +6268,14 @@ async function handleOntology(client2, args) {
|
|
|
6190
6268
|
// src/server.ts
|
|
6191
6269
|
function buildMindGraphServer(wiring) {
|
|
6192
6270
|
const { client: client2, hosted } = wiring;
|
|
6193
|
-
const
|
|
6271
|
+
const server = new import_server.Server(
|
|
6194
6272
|
{ name: "mindgraph", version: wiring.serverVersion },
|
|
6195
6273
|
{
|
|
6196
6274
|
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
6197
6275
|
instructions: wiring.instructions
|
|
6198
6276
|
}
|
|
6199
6277
|
);
|
|
6200
|
-
|
|
6278
|
+
server.setRequestHandler("tools/list", async () => {
|
|
6201
6279
|
const generated = await getGeneratedTools(client2, wiring.generatedTools);
|
|
6202
6280
|
const tools = [...toolsForProfile(wiring.profile), ...generated.tools];
|
|
6203
6281
|
if (!hosted) return { tools };
|
|
@@ -6208,9 +6286,14 @@ function buildMindGraphServer(wiring) {
|
|
|
6208
6286
|
]
|
|
6209
6287
|
};
|
|
6210
6288
|
});
|
|
6211
|
-
|
|
6289
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
6212
6290
|
const { name, arguments: args } = request.params;
|
|
6213
|
-
const rawArgs = {
|
|
6291
|
+
const rawArgs = {
|
|
6292
|
+
...args || {},
|
|
6293
|
+
// H1: session, lease and invocation fields the local hook recorded for
|
|
6294
|
+
// this exact call (stdio only; hosted mode has no local hook).
|
|
6295
|
+
...hosted ? {} : wiring.resolveHookFields?.(name, args || {})
|
|
6296
|
+
};
|
|
6214
6297
|
const toolArgs = { ...rawArgs };
|
|
6215
6298
|
let governanceConfig = wiring.governance;
|
|
6216
6299
|
if (hosted) {
|
|
@@ -6250,20 +6333,20 @@ function buildMindGraphServer(wiring) {
|
|
|
6250
6333
|
}
|
|
6251
6334
|
return handleTool(client2, name, toolArgs, wiring.memory);
|
|
6252
6335
|
});
|
|
6253
|
-
|
|
6336
|
+
server.setRequestHandler("prompts/list", async () => {
|
|
6254
6337
|
return { prompts: PROMPTS };
|
|
6255
6338
|
});
|
|
6256
|
-
|
|
6339
|
+
server.setRequestHandler("prompts/get", async (request) => {
|
|
6257
6340
|
const { name, arguments: args } = request.params;
|
|
6258
6341
|
return getPrompt(name, args);
|
|
6259
6342
|
});
|
|
6260
|
-
|
|
6343
|
+
server.setRequestHandler("resources/list", async () => {
|
|
6261
6344
|
return { resources: RESOURCES };
|
|
6262
6345
|
});
|
|
6263
|
-
|
|
6346
|
+
server.setRequestHandler("resources/templates/list", async () => {
|
|
6264
6347
|
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
6265
6348
|
});
|
|
6266
|
-
|
|
6349
|
+
server.setRequestHandler("resources/read", async (request) => {
|
|
6267
6350
|
return readGovernedResource(
|
|
6268
6351
|
client2,
|
|
6269
6352
|
request.params.uri,
|
|
@@ -6271,20 +6354,20 @@ function buildMindGraphServer(wiring) {
|
|
|
6271
6354
|
wiring.memory
|
|
6272
6355
|
);
|
|
6273
6356
|
});
|
|
6274
|
-
return
|
|
6357
|
+
return server;
|
|
6275
6358
|
}
|
|
6276
6359
|
|
|
6277
6360
|
// src/index.ts
|
|
6278
|
-
var
|
|
6361
|
+
var import_node_path6 = __toESM(require("path"));
|
|
6279
6362
|
|
|
6280
6363
|
// src/hook-installer.ts
|
|
6281
|
-
var
|
|
6282
|
-
var
|
|
6283
|
-
var
|
|
6284
|
-
var
|
|
6364
|
+
var import_node_fs5 = __toESM(require("fs"));
|
|
6365
|
+
var import_node_os4 = __toESM(require("os"));
|
|
6366
|
+
var import_node_path5 = __toESM(require("path"));
|
|
6367
|
+
var import_node_crypto7 = __toESM(require("crypto"));
|
|
6285
6368
|
function storedFeatures(homeDir) {
|
|
6286
6369
|
const { promptRecall, capture } = loadHookEnv(
|
|
6287
|
-
|
|
6370
|
+
import_node_path5.default.join(homeDir || import_node_os4.default.homedir(), ".mindgraph")
|
|
6288
6371
|
);
|
|
6289
6372
|
return { promptRecall, capture };
|
|
6290
6373
|
}
|
|
@@ -6298,24 +6381,24 @@ function windowsCommand(harness) {
|
|
|
6298
6381
|
}
|
|
6299
6382
|
var RUNNER_VERSION_RELATIVE = `${RUNNER_RELATIVE}.version`;
|
|
6300
6383
|
function installHookRunner(sourceFile, homeDir, version) {
|
|
6301
|
-
const target =
|
|
6302
|
-
|
|
6303
|
-
const temporary = `${target}.${process.pid}.${
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
const versionPath =
|
|
6384
|
+
const target = import_node_path5.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_RELATIVE);
|
|
6385
|
+
import_node_fs5.default.mkdirSync(import_node_path5.default.dirname(target), { recursive: true });
|
|
6386
|
+
const temporary = `${target}.${process.pid}.${import_node_crypto7.default.randomUUID()}.tmp`;
|
|
6387
|
+
import_node_fs5.default.copyFileSync(sourceFile, temporary);
|
|
6388
|
+
import_node_fs5.default.renameSync(temporary, target);
|
|
6389
|
+
const versionPath = import_node_path5.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_VERSION_RELATIVE);
|
|
6307
6390
|
if (version) {
|
|
6308
|
-
|
|
6391
|
+
import_node_fs5.default.writeFileSync(versionPath, `${version}
|
|
6309
6392
|
`);
|
|
6310
6393
|
} else {
|
|
6311
|
-
|
|
6394
|
+
import_node_fs5.default.rmSync(versionPath, { force: true });
|
|
6312
6395
|
}
|
|
6313
6396
|
return target;
|
|
6314
6397
|
}
|
|
6315
6398
|
function installedHookRunnerVersion(homeDir) {
|
|
6316
6399
|
try {
|
|
6317
|
-
const raw =
|
|
6318
|
-
|
|
6400
|
+
const raw = import_node_fs5.default.readFileSync(
|
|
6401
|
+
import_node_path5.default.join(homeDir || import_node_os4.default.homedir(), RUNNER_VERSION_RELATIVE),
|
|
6319
6402
|
"utf8"
|
|
6320
6403
|
).trim();
|
|
6321
6404
|
return raw || void 0;
|
|
@@ -6340,22 +6423,22 @@ function refreshHookRunner(serverVersion, sourceBundle, homeDir) {
|
|
|
6340
6423
|
if (process.env.MINDGRAPH_HOOK_AUTOUPDATE === "off") {
|
|
6341
6424
|
return { refreshed: false, reason: "disabled" };
|
|
6342
6425
|
}
|
|
6343
|
-
const home = homeDir ||
|
|
6344
|
-
if (!
|
|
6426
|
+
const home = homeDir || import_node_os4.default.homedir();
|
|
6427
|
+
if (!import_node_fs5.default.existsSync(import_node_path5.default.join(home, RUNNER_RELATIVE))) {
|
|
6345
6428
|
return { refreshed: false, reason: "no_runner" };
|
|
6346
6429
|
}
|
|
6347
|
-
if (!
|
|
6430
|
+
if (!import_node_fs5.default.existsSync(sourceBundle)) {
|
|
6348
6431
|
return { refreshed: false, reason: "no_source" };
|
|
6349
6432
|
}
|
|
6350
|
-
const
|
|
6351
|
-
if (!
|
|
6433
|
+
const server = parseSemver(serverVersion);
|
|
6434
|
+
if (!server) return { refreshed: false, reason: "unparseable" };
|
|
6352
6435
|
const runnerVersion = installedHookRunnerVersion(home);
|
|
6353
6436
|
if (runnerVersion !== void 0) {
|
|
6354
6437
|
const pinned = parseSemver(runnerVersion);
|
|
6355
6438
|
if (!pinned) {
|
|
6356
6439
|
return { refreshed: false, reason: "unparseable", runnerVersion };
|
|
6357
6440
|
}
|
|
6358
|
-
if (!semverNewer(
|
|
6441
|
+
if (!semverNewer(server, pinned)) {
|
|
6359
6442
|
return {
|
|
6360
6443
|
refreshed: false,
|
|
6361
6444
|
reason: runnerVersion === serverVersion ? "current" : "downgrade",
|
|
@@ -6375,8 +6458,8 @@ function refreshOwnedClaudeHooks(projectDir = process.cwd(), homeDir) {
|
|
|
6375
6458
|
for (const scope of scopes) {
|
|
6376
6459
|
try {
|
|
6377
6460
|
const file = settingsPath("claude-code", scope, projectDir, void 0, homeDir);
|
|
6378
|
-
if (!
|
|
6379
|
-
if (!
|
|
6461
|
+
if (!import_node_fs5.default.existsSync(file)) continue;
|
|
6462
|
+
if (!import_node_fs5.default.readFileSync(file, "utf8").includes(OWNER_MARKER)) continue;
|
|
6380
6463
|
installHooks(
|
|
6381
6464
|
"claude-code",
|
|
6382
6465
|
scope,
|
|
@@ -6396,15 +6479,15 @@ function versionSkewNote(serverVersion, homeDir) {
|
|
|
6396
6479
|
if (!runnerVersion || runnerVersion === serverVersion) return void 0;
|
|
6397
6480
|
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).`;
|
|
6398
6481
|
}
|
|
6399
|
-
function settingsPath(harness, scope, projectDir = process.cwd(), codexHomeDir = process.env.CODEX_HOME ||
|
|
6482
|
+
function settingsPath(harness, scope, projectDir = process.cwd(), codexHomeDir = process.env.CODEX_HOME || import_node_path5.default.join(import_node_os4.default.homedir(), ".codex"), homeDir) {
|
|
6400
6483
|
if (harness === "codex") {
|
|
6401
|
-
return scope === "user" ?
|
|
6484
|
+
return scope === "user" ? import_node_path5.default.join(codexHomeDir, "hooks.json") : import_node_path5.default.join(projectDir, ".codex", "hooks.json");
|
|
6402
6485
|
}
|
|
6403
|
-
return scope === "user" ?
|
|
6486
|
+
return scope === "user" ? import_node_path5.default.join(homeDir || import_node_os4.default.homedir(), ".claude", "settings.json") : import_node_path5.default.join(projectDir, ".claude", "settings.json");
|
|
6404
6487
|
}
|
|
6405
6488
|
function readSettings(file) {
|
|
6406
|
-
if (!
|
|
6407
|
-
return JSON.parse(
|
|
6489
|
+
if (!import_node_fs5.default.existsSync(file)) return {};
|
|
6490
|
+
return JSON.parse(import_node_fs5.default.readFileSync(file, "utf8"));
|
|
6408
6491
|
}
|
|
6409
6492
|
function ownedHook(harness, timeout, additionalContextLimit) {
|
|
6410
6493
|
return {
|
|
@@ -6416,6 +6499,7 @@ function ownedHook(harness, timeout, additionalContextLimit) {
|
|
|
6416
6499
|
...additionalContextLimit === void 0 ? {} : { additionalContextLimit }
|
|
6417
6500
|
};
|
|
6418
6501
|
}
|
|
6502
|
+
var CLAUDE_POST_TOOL_MATCHER = "mcp__mindgraph__.*|Edit|MultiEdit|Write|NotebookEdit|Bash|Task|Agent";
|
|
6419
6503
|
function desiredEntries(harness, features = {}) {
|
|
6420
6504
|
const common = {
|
|
6421
6505
|
SessionStart: [
|
|
@@ -6448,7 +6532,17 @@ function desiredEntries(harness, features = {}) {
|
|
|
6448
6532
|
],
|
|
6449
6533
|
// PostToolUse awaits the lease renewal round-trip, which fires exactly
|
|
6450
6534
|
// when the tenant is cold (post-idle reclaim) — 5s killed it mid-claim.
|
|
6451
|
-
|
|
6535
|
+
// Claude Code: only the tools the hook acts on (MindGraph calls, edits,
|
|
6536
|
+
// and the shell/agent calls that keep a lease alive). Read, Grep and Glob
|
|
6537
|
+
// are most of a session's tool calls and the hook did nothing useful for
|
|
6538
|
+
// them but start a process (roadmap H8). Codex names its tools
|
|
6539
|
+
// differently, so it keeps the catch-all.
|
|
6540
|
+
PostToolUse: [
|
|
6541
|
+
{
|
|
6542
|
+
matcher: harness === "claude-code" ? CLAUDE_POST_TOOL_MATCHER : ".*",
|
|
6543
|
+
hooks: [ownedHook(harness, 10)]
|
|
6544
|
+
}
|
|
6545
|
+
],
|
|
6452
6546
|
Stop: [{ hooks: [ownedHook(harness, 5)] }],
|
|
6453
6547
|
// SessionEnd makes up to two sequential cloud calls (abandon_iteration +
|
|
6454
6548
|
// session close) — the SAME cold-tenant latency SessionStart needs 30s
|
|
@@ -6482,13 +6576,13 @@ function entryHasOwnedHook(value) {
|
|
|
6482
6576
|
return Array.isArray(hooks) && hooks.some((hook) => hookCommand(hook)?.includes(OWNER_MARKER));
|
|
6483
6577
|
}
|
|
6484
6578
|
function writeSettings(file, settings) {
|
|
6485
|
-
|
|
6486
|
-
const temporary = `${file}.${process.pid}.${
|
|
6487
|
-
|
|
6579
|
+
import_node_fs5.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
|
|
6580
|
+
const temporary = `${file}.${process.pid}.${import_node_crypto7.default.randomUUID()}.tmp`;
|
|
6581
|
+
import_node_fs5.default.writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}
|
|
6488
6582
|
`, {
|
|
6489
6583
|
mode: 384
|
|
6490
6584
|
});
|
|
6491
|
-
|
|
6585
|
+
import_node_fs5.default.renameSync(temporary, file);
|
|
6492
6586
|
}
|
|
6493
6587
|
function installHooks(harness, scope, projectDir = process.cwd(), codexHomeDir, homeDir, features = {}) {
|
|
6494
6588
|
const file = settingsPath(harness, scope, projectDir, codexHomeDir, homeDir);
|
|
@@ -6613,7 +6707,7 @@ if (PROFILE === "coding") {
|
|
|
6613
6707
|
- Capture corrections, decisions with rationale, fixes that survived meaningful failed attempts, durable invariants/preferences, and blockers with evidence.
|
|
6614
6708
|
- If a write returns \`near_duplicate\`, choose \`reuse_uid\` or \`supersedes_uid\`; use \`confirm_new\` only for genuinely distinct facts.
|
|
6615
6709
|
- Do not capture routine mechanics, transient command output, facts cheaply derivable from code, unsupported speculation as high-confidence lessons, or completion without evidence.
|
|
6616
|
-
- Adapter context is owned by ${HARNESS}; omit invocation_context because
|
|
6710
|
+
- Adapter context is owned by ${HARNESS}; omit invocation_context because the adapter supplies it.`;
|
|
6617
6711
|
} else {
|
|
6618
6712
|
INSTRUCTIONS = INSTRUCTIONS.split("\n").filter(
|
|
6619
6713
|
(line) => !line.includes("mindgraph_code") && !line.includes("`code`") && !line.includes("Typed code anchors")
|
|
@@ -6621,7 +6715,7 @@ if (PROFILE === "coding") {
|
|
|
6621
6715
|
}
|
|
6622
6716
|
var RUNNER_REFRESH = (() => {
|
|
6623
6717
|
try {
|
|
6624
|
-
return refreshHookRunner("0.
|
|
6718
|
+
return refreshHookRunner("0.25.0", import_node_path6.default.join(__dirname, "cli.js"));
|
|
6625
6719
|
} catch {
|
|
6626
6720
|
return void 0;
|
|
6627
6721
|
}
|
|
@@ -6635,12 +6729,12 @@ if (RUNNER_REFRESH?.refreshed) {
|
|
|
6635
6729
|
}
|
|
6636
6730
|
})();
|
|
6637
6731
|
console.error(
|
|
6638
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
6732
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.25.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
6639
6733
|
);
|
|
6640
6734
|
}
|
|
6641
6735
|
var HOOK_SKEW_NOTE = (() => {
|
|
6642
6736
|
try {
|
|
6643
|
-
return versionSkewNote("0.
|
|
6737
|
+
return versionSkewNote("0.25.0");
|
|
6644
6738
|
} catch {
|
|
6645
6739
|
return void 0;
|
|
6646
6740
|
}
|
|
@@ -6661,27 +6755,29 @@ var GOVERNANCE_CONFIG = {
|
|
|
6661
6755
|
}
|
|
6662
6756
|
};
|
|
6663
6757
|
var MEMORY_RUNTIME_CONFIG = {
|
|
6664
|
-
serverVersion: "0.
|
|
6758
|
+
serverVersion: "0.25.0",
|
|
6665
6759
|
baseUrl: BASE_URL,
|
|
6666
6760
|
profile: PROFILE,
|
|
6667
6761
|
harness: HARNESS,
|
|
6668
6762
|
orgId: ORG_ID,
|
|
6669
6763
|
agentId: AGENT_ID
|
|
6670
6764
|
};
|
|
6671
|
-
var
|
|
6765
|
+
var buildServer = () => buildMindGraphServer({
|
|
6672
6766
|
client,
|
|
6673
|
-
serverVersion: "0.
|
|
6767
|
+
serverVersion: "0.25.0",
|
|
6674
6768
|
instructions: INSTRUCTIONS,
|
|
6675
6769
|
profile: PROFILE,
|
|
6676
6770
|
agentId: AGENT_ID,
|
|
6677
6771
|
governance: GOVERNANCE_CONFIG,
|
|
6678
|
-
memory: MEMORY_RUNTIME_CONFIG
|
|
6772
|
+
memory: MEMORY_RUNTIME_CONFIG,
|
|
6773
|
+
resolveHookFields: (name, args) => resolvePendingCall(name, args)
|
|
6679
6774
|
});
|
|
6680
6775
|
async function main() {
|
|
6681
|
-
|
|
6682
|
-
|
|
6776
|
+
(0, import_stdio.serveStdio)(buildServer, {
|
|
6777
|
+
onerror: (error2) => console.error("MindGraph MCP transport error:", error2.message)
|
|
6778
|
+
});
|
|
6683
6779
|
console.error(
|
|
6684
|
-
`MindGraph MCP server v${"0.
|
|
6780
|
+
`MindGraph MCP server v${"0.25.0"} running on stdio (${BASE_URL})`
|
|
6685
6781
|
);
|
|
6686
6782
|
}
|
|
6687
6783
|
main().catch((error2) => {
|