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/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/index.ts
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 = import_node_os.default.userInfo().username || "user";
92
+ user = import_node_os2.default.userInfo().username || "user";
38
93
  } catch {
39
94
  }
40
- const digest = import_node_crypto.default.createHash("sha256").update(`${user}@${import_node_os.default.hostname()}`).digest("hex").slice(0, 12);
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 import_node_path.default.join(dir || import_node_path.default.join(import_node_os.default.homedir(), ".mindgraph"), "hooks.json");
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 = import_node_fs.default.readFileSync(hookEnvPath(dir), "utf8");
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/sdk/server/index.js");
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((path5) => Boolean(path5)).map((path5, index) => {
583
- const uids = Array.isArray(path5.node_uids) ? path5.node_uids.map(String) : [];
584
- const labels = Array.isArray(path5.labels) ? path5.labels.map(String) : Array.isArray(path5.nodes) ? path5.nodes.map((hop) => {
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(path5.cost) ?? num(path5.path_cost);
590
- const confidence = num(path5.path_confidence);
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 import_node_crypto2 = require("crypto");
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 stableJson(value) {
1741
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
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)}:${stableJson(item)}`).join(",")}}`;
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, import_node_crypto2.createHash)("sha256").update(value).digest("hex");
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
- stableJson({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
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 import_node_crypto5 = require("crypto");
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 import_node_fs2 = require("fs");
2280
+ var import_node_fs3 = require("fs");
2220
2281
  var import_promises = require("fs/promises");
2221
- var import_node_os2 = require("os");
2222
- var import_node_path2 = require("path");
2223
- var import_node_crypto3 = require("crypto");
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(path5) {
2255
- return path5.replaceAll("\\", "/").replace(/^\.\//, "");
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(path5) {
2261
- const extension = (0, import_node_path2.extname)(path5).toLowerCase();
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, import_node_path2.relative)(root, candidate);
2311
- return child === "" || child !== ".." && !child.startsWith(`..${import_node_path2.sep}`) && !(0, import_node_path2.isAbsolute)(child);
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, import_node_path2.resolve)(candidate);
2375
+ let current = (0, import_node_path3.resolve)(candidate);
2315
2376
  for (; ; ) {
2316
- if ((0, import_node_fs2.existsSync)(current)) {
2377
+ if ((0, import_node_fs3.existsSync)(current)) {
2317
2378
  try {
2318
- return (0, import_node_fs2.statSync)(current).isDirectory() ? current : (0, import_node_path2.dirname)(current);
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, import_node_path2.dirname)(current);
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, import_node_path2.resolve)(start, explicit);
2329
- let current = (0, import_node_path2.resolve)(start);
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, import_node_path2.join)(current, ".mindgraph", "workspace.json");
2332
- if ((0, import_node_fs2.existsSync)(candidate)) return candidate;
2333
- const parent = (0, import_node_path2.dirname)(current);
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, import_node_path2.basename)(candidate.repoRoot) === repo
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, import_node_path2.resolve)(this.cwd, repo)).catch(
2431
- () => (0, import_node_path2.resolve)(this.cwd, repo)
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, import_node_fs2.existsSync)(requestedPath)) {
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, import_node_path2.resolve)(this.cwd, requestedRoot)).catch(
2450
- () => (0, import_node_path2.resolve)(this.cwd, requestedRoot)
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, import_node_path2.resolve)(root));
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, import_node_path2.basename)(repoRoot)}`;
2562
+ return `local:${(0, import_node_path3.basename)(repoRoot)}`;
2502
2563
  }
2503
- const commonDir = (0, import_node_path2.resolve)(repoRoot, rawCommonDir.trim());
2504
- const identityDir = (0, import_node_path2.join)(commonDir, "mindgraph");
2505
- const identityFile = (0, import_node_path2.join)(identityDir, "repository-id");
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, import_node_fs2.readFileSync)(identityFile, "utf8").trim();
2568
+ const existing = (0, import_node_fs3.readFileSync)(identityFile, "utf8").trim();
2508
2569
  if (existing) return existing;
2509
2570
  } catch {
2510
2571
  }
2511
- (0, import_node_fs2.mkdirSync)(identityDir, { recursive: true, mode: 448 });
2512
- const generated = (0, import_node_crypto3.randomUUID)();
2572
+ (0, import_node_fs3.mkdirSync)(identityDir, { recursive: true, mode: 448 });
2573
+ const generated = (0, import_node_crypto4.randomUUID)();
2513
2574
  try {
2514
- (0, import_node_fs2.writeFileSync)(identityFile, `${generated}
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, import_node_fs2.readFileSync)(identityFile, "utf8").trim();
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, import_node_path2.resolve)(start, raw.trim()) : void 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, import_node_fs2.existsSync)(this.workspaceFile)) {
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, import_node_path2.isAbsolute)(ref.path) ? (0, import_node_path2.resolve)(ref.path) : (0, import_node_path2.resolve)(this.cwd, ref.path);
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, import_node_fs2.existsSync)(this.workspaceFile)) {
2799
+ if (this.workspaceFile && (0, import_node_fs3.existsSync)(this.workspaceFile)) {
2739
2800
  try {
2740
2801
  const parsed = JSON.parse(
2741
- (0, import_node_fs2.readFileSync)(this.workspaceFile, "utf8")
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, import_node_path2.dirname)(this.workspaceFile);
2745
- const base = (0, import_node_path2.basename)(configDirectory) === ".mindgraph" ? (0, import_node_path2.dirname)(configDirectory) : configDirectory;
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, import_node_path2.resolve)(base, repository.root),
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, import_node_path2.resolve)(
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, import_node_path2.isAbsolute)(ref.path) ? await (0, import_promises.realpath)(ref.path).catch(() => ref.path) : void 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, import_node_path2.relative)(repository.repoRoot, absolutePath) : ref.path
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, import_node_path2.resolve)((0, import_node_os2.homedir)(), ".local", "bin", "codegraph")
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 import_node_crypto4 = __toESM(require("crypto"));
3498
- var import_node_fs3 = __toESM(require("fs"));
3499
- var import_node_path3 = __toESM(require("path"));
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 = import_node_path3.default.resolve(root, candidate);
3577
- const relative2 = import_node_path3.default.relative(root, absolute);
3578
- if (relative2.startsWith("..") || import_node_path3.default.isAbsolute(relative2)) {
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 (import_node_fs3.default.existsSync(absolute)) {
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 import_node_fs3.default.realpathSync(target);
3651
+ return import_node_fs4.default.realpathSync(target);
3591
3652
  } catch {
3592
- return import_node_path3.default.resolve(target);
3653
+ return import_node_path4.default.resolve(target);
3593
3654
  }
3594
3655
  }
3595
3656
  function markdownFiles(target, realRoot, visited = /* @__PURE__ */ new Set()) {
3596
- if (!import_node_fs3.default.existsSync(target)) return [];
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 = import_node_fs3.default.statSync(target);
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 import_node_fs3.default.readdirSync(target, { withFileTypes: true }).flatMap((entry) => markdownFiles(import_node_path3.default.join(target, entry.name), realRoot, visited));
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 = import_node_fs3.default.readFileSync(absolute, "utf8");
3667
+ const content = import_node_fs4.default.readFileSync(absolute, "utf8");
3607
3668
  return {
3608
- logical_path: import_node_path3.default.relative(root, absolute).split(import_node_path3.default.sep).join("/"),
3609
- content_hash: import_node_crypto4.default.createHash("sha256").update(content).digest("hex"),
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 = import_node_fs3.default.existsSync(absolute);
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 stableJson2(value) {
3752
- if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
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)}:${stableJson2(item)}`).join(",")}}`;
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, import_node_crypto5.createHash)("sha256").update(
3769
- stableJson2({
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 server2 = new import_server.Server(
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
- server2.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
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
- server2.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
6289
+ server.setRequestHandler("tools/call", async (request) => {
6212
6290
  const { name, arguments: args } = request.params;
6213
- const rawArgs = { ...args || {} };
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
- server2.setRequestHandler(import_types.ListPromptsRequestSchema, async () => {
6336
+ server.setRequestHandler("prompts/list", async () => {
6254
6337
  return { prompts: PROMPTS };
6255
6338
  });
6256
- server2.setRequestHandler(import_types.GetPromptRequestSchema, async (request) => {
6339
+ server.setRequestHandler("prompts/get", async (request) => {
6257
6340
  const { name, arguments: args } = request.params;
6258
6341
  return getPrompt(name, args);
6259
6342
  });
6260
- server2.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
6343
+ server.setRequestHandler("resources/list", async () => {
6261
6344
  return { resources: RESOURCES };
6262
6345
  });
6263
- server2.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async () => {
6346
+ server.setRequestHandler("resources/templates/list", async () => {
6264
6347
  return { resourceTemplates: RESOURCE_TEMPLATES };
6265
6348
  });
6266
- server2.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
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 server2;
6357
+ return server;
6275
6358
  }
6276
6359
 
6277
6360
  // src/index.ts
6278
- var import_node_path5 = __toESM(require("path"));
6361
+ var import_node_path6 = __toESM(require("path"));
6279
6362
 
6280
6363
  // src/hook-installer.ts
6281
- var import_node_fs4 = __toESM(require("fs"));
6282
- var import_node_os3 = __toESM(require("os"));
6283
- var import_node_path4 = __toESM(require("path"));
6284
- var import_node_crypto6 = __toESM(require("crypto"));
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
- import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), ".mindgraph")
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 = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_RELATIVE);
6302
- import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(target), { recursive: true });
6303
- const temporary = `${target}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
6304
- import_node_fs4.default.copyFileSync(sourceFile, temporary);
6305
- import_node_fs4.default.renameSync(temporary, target);
6306
- const versionPath = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_VERSION_RELATIVE);
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
- import_node_fs4.default.writeFileSync(versionPath, `${version}
6391
+ import_node_fs5.default.writeFileSync(versionPath, `${version}
6309
6392
  `);
6310
6393
  } else {
6311
- import_node_fs4.default.rmSync(versionPath, { force: true });
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 = import_node_fs4.default.readFileSync(
6318
- import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_VERSION_RELATIVE),
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 || import_node_os3.default.homedir();
6344
- if (!import_node_fs4.default.existsSync(import_node_path4.default.join(home, RUNNER_RELATIVE))) {
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 (!import_node_fs4.default.existsSync(sourceBundle)) {
6430
+ if (!import_node_fs5.default.existsSync(sourceBundle)) {
6348
6431
  return { refreshed: false, reason: "no_source" };
6349
6432
  }
6350
- const server2 = parseSemver(serverVersion);
6351
- if (!server2) return { refreshed: false, reason: "unparseable" };
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(server2, pinned)) {
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 (!import_node_fs4.default.existsSync(file)) continue;
6379
- if (!import_node_fs4.default.readFileSync(file, "utf8").includes(OWNER_MARKER)) continue;
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 || import_node_path4.default.join(import_node_os3.default.homedir(), ".codex"), homeDir) {
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" ? import_node_path4.default.join(codexHomeDir, "hooks.json") : import_node_path4.default.join(projectDir, ".codex", "hooks.json");
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" ? import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), ".claude", "settings.json") : import_node_path4.default.join(projectDir, ".claude", "settings.json");
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 (!import_node_fs4.default.existsSync(file)) return {};
6407
- return JSON.parse(import_node_fs4.default.readFileSync(file, "utf8"));
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
- PostToolUse: [{ matcher: ".*", hooks: [ownedHook(harness, 10)] }],
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
- import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
6486
- const temporary = `${file}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
6487
- import_node_fs4.default.writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}
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
- import_node_fs4.default.renameSync(temporary, file);
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 hooks replace it.`;
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.23.0", import_node_path5.default.join(__dirname, "cli.js"));
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.23.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
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.23.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.23.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 server = buildMindGraphServer({
6765
+ var buildServer = () => buildMindGraphServer({
6672
6766
  client,
6673
- serverVersion: "0.23.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
- const transport = new import_stdio.StdioServerTransport();
6682
- await server.connect(transport);
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.23.0"} running on stdio (${BASE_URL})`
6780
+ `MindGraph MCP server v${"0.25.0"} running on stdio (${BASE_URL})`
6685
6781
  );
6686
6782
  }
6687
6783
  main().catch((error2) => {