mindgraph-mcp 0.13.5 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +71 -3
  3. package/dist/cli.js +2941 -216
  4. package/dist/index.js +2145 -160
  5. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,22 +1,1439 @@
1
1
  "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
2
24
 
3
25
  // src/index.ts
4
26
  var import_server = require("@modelcontextprotocol/sdk/server/index.js");
5
27
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6
28
  var import_types = require("@modelcontextprotocol/sdk/types.js");
29
+ var import_mindgraph2 = require("mindgraph");
30
+
31
+ // src/error-detail.ts
7
32
  var import_mindgraph = require("mindgraph");
33
+ function errorDetail(e) {
34
+ if (e instanceof import_mindgraph.MindGraphError && e.body !== void 0) {
35
+ const detail = typeof e.body === "string" ? e.body : JSON.stringify(e.body);
36
+ return `${e.message} \u2014 ${detail}`;
37
+ }
38
+ return e instanceof Error ? e.message : String(e);
39
+ }
40
+
41
+ // src/codegraph.ts
42
+ var import_node_child_process = require("child_process");
43
+ var import_node_fs = require("fs");
44
+ var import_promises = require("fs/promises");
45
+ var import_node_os = require("os");
46
+ var import_node_path = require("path");
47
+ var import_node_crypto = require("crypto");
48
+ var DEFAULT_TIMEOUT_MS = 5e3;
49
+ var DEFAULT_STATUS_TTL_MS = 6e4;
50
+ var MAX_OUTPUT_BYTES = 5 * 1024 * 1024;
51
+ function normalizePath(path2) {
52
+ return path2.replaceAll("\\", "/").replace(/^\.\//, "");
53
+ }
54
+ function normalizeSignature(signature) {
55
+ return signature.replace(/\s+/g, " ").trim();
56
+ }
57
+ function languageFromPath(path2) {
58
+ const extension = (0, import_node_path.extname)(path2).toLowerCase();
59
+ return {
60
+ ".c": "c",
61
+ ".cc": "cpp",
62
+ ".cpp": "cpp",
63
+ ".go": "go",
64
+ ".java": "java",
65
+ ".js": "javascript",
66
+ ".jsx": "javascript",
67
+ ".kt": "kotlin",
68
+ ".py": "python",
69
+ ".rb": "ruby",
70
+ ".rs": "rust",
71
+ ".swift": "swift",
72
+ ".ts": "typescript",
73
+ ".tsx": "typescript"
74
+ }[extension] ?? "unknown";
75
+ }
76
+ function asNode(hit) {
77
+ return hit.node ?? hit;
78
+ }
79
+ function toCandidate(node) {
80
+ if (!node.filePath || !node.kind || !(node.qualifiedName || node.name)) return null;
81
+ return {
82
+ path: normalizePath(node.filePath),
83
+ language: node.language ?? languageFromPath(node.filePath),
84
+ kind: node.kind,
85
+ qualifiedName: node.qualifiedName ?? node.name ?? "",
86
+ signature: node.signature ?? null,
87
+ startLine: node.startLine ?? 1,
88
+ endLine: node.endLine ?? node.startLine ?? 1
89
+ };
90
+ }
91
+ function normalizeRemote(remote) {
92
+ const trimmed = remote.trim();
93
+ if (!trimmed) return null;
94
+ const scp = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(trimmed);
95
+ if (scp && !trimmed.includes("://")) {
96
+ return `${scp[1].toLowerCase()}/${scp[2].replace(/\.git$/, "")}`;
97
+ }
98
+ try {
99
+ const url = new URL(trimmed);
100
+ const pathname = url.pathname.replace(/\/$/, "").replace(/\.git$/, "");
101
+ return `${url.host.toLowerCase()}${pathname}`;
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ function pathContains(root, candidate) {
107
+ const child = (0, import_node_path.relative)(root, candidate);
108
+ return child === "" || child !== ".." && !child.startsWith(`..${import_node_path.sep}`) && !(0, import_node_path.isAbsolute)(child);
109
+ }
110
+ function nearestExistingDirectory(candidate) {
111
+ let current = (0, import_node_path.resolve)(candidate);
112
+ for (; ; ) {
113
+ if ((0, import_node_fs.existsSync)(current)) {
114
+ try {
115
+ return (0, import_node_fs.statSync)(current).isDirectory() ? current : (0, import_node_path.dirname)(current);
116
+ } catch {
117
+ }
118
+ }
119
+ const parent = (0, import_node_path.dirname)(current);
120
+ if (parent === current) return current;
121
+ current = parent;
122
+ }
123
+ }
124
+ function findWorkspaceFile(start, explicit) {
125
+ if (explicit) return (0, import_node_path.resolve)(start, explicit);
126
+ let current = (0, import_node_path.resolve)(start);
127
+ for (; ; ) {
128
+ const candidate = (0, import_node_path.join)(current, ".mindgraph", "workspace.json");
129
+ if ((0, import_node_fs.existsSync)(candidate)) return candidate;
130
+ const parent = (0, import_node_path.dirname)(current);
131
+ if (parent === current) return void 0;
132
+ current = parent;
133
+ }
134
+ }
135
+ async function runProcess(executable, args, timeoutMs, env, cwd) {
136
+ return await new Promise((resolvePromise, rejectPromise) => {
137
+ const child = (0, import_node_child_process.spawn)(executable, args, {
138
+ cwd,
139
+ env,
140
+ stdio: ["ignore", "pipe", "pipe"],
141
+ windowsHide: true
142
+ });
143
+ const stdout = [];
144
+ const stderr = [];
145
+ let outputBytes = 0;
146
+ let timedOut = false;
147
+ const timer = setTimeout(() => {
148
+ timedOut = true;
149
+ child.kill("SIGTERM");
150
+ setTimeout(() => child.kill("SIGKILL"), 250).unref();
151
+ }, timeoutMs);
152
+ timer.unref();
153
+ const collect = (target) => (chunk) => {
154
+ outputBytes += chunk.length;
155
+ if (outputBytes > MAX_OUTPUT_BYTES) {
156
+ child.kill("SIGTERM");
157
+ return;
158
+ }
159
+ target.push(chunk);
160
+ };
161
+ child.stdout.on("data", collect(stdout));
162
+ child.stderr.on("data", collect(stderr));
163
+ child.on("error", (cause) => {
164
+ clearTimeout(timer);
165
+ const error = new Error(cause.message);
166
+ error.kind = cause.code === "ENOENT" ? "absent" : "command_failed";
167
+ rejectPromise(error);
168
+ });
169
+ child.on("close", (code) => {
170
+ clearTimeout(timer);
171
+ if (timedOut) {
172
+ const error = new Error(`command timed out after ${timeoutMs}ms`);
173
+ error.kind = "timeout";
174
+ rejectPromise(error);
175
+ return;
176
+ }
177
+ if (outputBytes > MAX_OUTPUT_BYTES) {
178
+ const error = new Error("codegraph output exceeded 5 MiB");
179
+ error.kind = "command_failed";
180
+ rejectPromise(error);
181
+ return;
182
+ }
183
+ if (code !== 0) {
184
+ const error = new Error(Buffer.concat(stderr).toString("utf8").trim());
185
+ error.kind = "command_failed";
186
+ error.exitCode = code;
187
+ rejectPromise(error);
188
+ return;
189
+ }
190
+ resolvePromise(Buffer.concat(stdout).toString("utf8"));
191
+ });
192
+ });
193
+ }
194
+ var CodegraphAdapter = class {
195
+ timeoutMs;
196
+ statusTtlMs;
197
+ env;
198
+ cwd;
199
+ workspaceFile;
200
+ now;
201
+ identityCache = /* @__PURE__ */ new Map();
202
+ statusCache = /* @__PURE__ */ new Map();
203
+ constructor(options = {}) {
204
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
205
+ this.statusTtlMs = options.statusTtlMs ?? DEFAULT_STATUS_TTL_MS;
206
+ this.env = options.env ?? process.env;
207
+ this.cwd = options.cwd ?? process.cwd();
208
+ this.workspaceFile = findWorkspaceFile(
209
+ this.cwd,
210
+ options.workspaceFile ?? this.env.MINDGRAPH_WORKSPACE_FILE
211
+ );
212
+ this.now = options.now ?? Date.now;
213
+ }
214
+ async resolveRepository(repo, fallbackSpaceUid) {
215
+ const configured = await this.resolveRepositories(fallbackSpaceUid);
216
+ const selected = repo && configured.find((candidate) => candidate.repoId === repo) || repo && configured.find(
217
+ (candidate) => candidate.repoRoot === repo || (0, import_node_path.basename)(candidate.repoRoot) === repo
218
+ ) || (!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);
219
+ if (selected) {
220
+ return !repo && this.env.MINDGRAPH_REPO_ID ? this.resolveRepositoryIdentity(
221
+ selected.repoRoot,
222
+ this.env.MINDGRAPH_REPO_ID,
223
+ selected.spaceUid
224
+ ) : selected;
225
+ }
226
+ const requestedRoot = repo || this.env.MINDGRAPH_REPO_ROOT || this.cwd;
227
+ const requestedPath = await (0, import_promises.realpath)((0, import_node_path.resolve)(this.cwd, requestedRoot)).catch(
228
+ () => (0, import_node_path.resolve)(this.cwd, requestedRoot)
229
+ );
230
+ const repoRoot = await this.gitRoot(requestedPath) ?? requestedPath;
231
+ return this.resolveRepositoryIdentity(
232
+ repoRoot,
233
+ this.env.MINDGRAPH_REPO_ID,
234
+ this.env.MINDGRAPH_CODE_SPACE_UID || fallbackSpaceUid
235
+ );
236
+ }
237
+ async resolveRepositories(fallbackSpaceUid) {
238
+ return Promise.all(
239
+ this.configuredRepositories().map(
240
+ (repository) => this.resolveRepositoryIdentity(
241
+ repository.repoRoot,
242
+ repository.repoId,
243
+ repository.spaceUid || this.env.MINDGRAPH_CODE_SPACE_UID || fallbackSpaceUid
244
+ )
245
+ )
246
+ );
247
+ }
248
+ async resolveRepositoryIdentity(root, explicitRepoId, spaceUid) {
249
+ const repoRoot = await (0, import_promises.realpath)(root).catch(() => (0, import_node_path.resolve)(root));
250
+ const cacheKey = `${repoRoot}\0${explicitRepoId ?? ""}\0${spaceUid ?? ""}`;
251
+ const cached = this.identityCache.get(cacheKey);
252
+ if (cached) return cached;
253
+ const pending = this.loadRepositoryIdentity(repoRoot, explicitRepoId, spaceUid);
254
+ this.identityCache.set(cacheKey, pending);
255
+ return pending;
256
+ }
257
+ async loadRepositoryIdentity(repoRoot, explicitRepoId, spaceUid) {
258
+ const remote = await runProcess(
259
+ "git",
260
+ ["-C", repoRoot, "config", "--get", "remote.origin.url"],
261
+ Math.min(this.timeoutMs, 2e3),
262
+ this.env
263
+ ).catch(() => "");
264
+ const repoId = explicitRepoId || normalizeRemote(remote) || await this.persistedRepositoryId(repoRoot);
265
+ return {
266
+ repoId,
267
+ repoRoot,
268
+ spaceUid
269
+ };
270
+ }
271
+ async persistedRepositoryId(repoRoot) {
272
+ const rawCommonDir = await runProcess(
273
+ "git",
274
+ ["-C", repoRoot, "rev-parse", "--git-common-dir"],
275
+ Math.min(this.timeoutMs, 2e3),
276
+ this.env
277
+ ).catch(() => "");
278
+ if (!rawCommonDir.trim()) {
279
+ return `local:${(0, import_node_path.basename)(repoRoot)}`;
280
+ }
281
+ const commonDir = (0, import_node_path.resolve)(repoRoot, rawCommonDir.trim());
282
+ const identityDir = (0, import_node_path.join)(commonDir, "mindgraph");
283
+ const identityFile = (0, import_node_path.join)(identityDir, "repository-id");
284
+ try {
285
+ const existing = (0, import_node_fs.readFileSync)(identityFile, "utf8").trim();
286
+ if (existing) return existing;
287
+ } catch {
288
+ }
289
+ (0, import_node_fs.mkdirSync)(identityDir, { recursive: true, mode: 448 });
290
+ const generated = (0, import_node_crypto.randomUUID)();
291
+ try {
292
+ (0, import_node_fs.writeFileSync)(identityFile, `${generated}
293
+ `, {
294
+ encoding: "utf8",
295
+ flag: "wx",
296
+ mode: 384
297
+ });
298
+ return generated;
299
+ } catch (cause) {
300
+ if (cause.code !== "EEXIST") throw cause;
301
+ const winner = (0, import_node_fs.readFileSync)(identityFile, "utf8").trim();
302
+ if (!winner) throw new Error(`empty repository identity file: ${identityFile}`);
303
+ return winner;
304
+ }
305
+ }
306
+ async gitRoot(candidate) {
307
+ const start = nearestExistingDirectory(candidate);
308
+ const raw = await runProcess(
309
+ "git",
310
+ ["-C", start, "rev-parse", "--show-toplevel"],
311
+ Math.min(this.timeoutMs, 2e3),
312
+ this.env
313
+ ).catch(() => "");
314
+ return raw.trim() ? (0, import_node_path.resolve)(start, raw.trim()) : void 0;
315
+ }
316
+ async availability(repository) {
317
+ const cached = this.statusCache.get(repository.repoRoot);
318
+ if (cached && cached.expiresAt > this.now()) return cached.availability;
319
+ try {
320
+ const status = await this.runJson([
321
+ "status",
322
+ repository.repoRoot,
323
+ "-j"
324
+ ]);
325
+ const caveats = [];
326
+ let availability;
327
+ if (status.worktreeMismatch != null) {
328
+ availability = {
329
+ available: false,
330
+ reason: "wrong_index",
331
+ stale: false,
332
+ caveats: ["the index belongs to a different worktree"],
333
+ lastIndexed: status.lastIndexed
334
+ };
335
+ } else if (!status.initialized || status.index?.state !== "complete") {
336
+ availability = {
337
+ available: false,
338
+ reason: "index_incomplete",
339
+ stale: false,
340
+ caveats: [
341
+ !status.initialized ? "codegraph is not initialized for this repository" : `codegraph index state is ${status.index?.state ?? "unknown"}`
342
+ ],
343
+ lastIndexed: status.lastIndexed
344
+ };
345
+ } else {
346
+ const pending = (status.pendingChanges?.added ?? 0) + (status.pendingChanges?.modified ?? 0) + (status.pendingChanges?.removed ?? 0);
347
+ if (pending > 0) caveats.push(`${pending} worktree changes are not indexed`);
348
+ if ((status.index?.pendingRefs ?? 0) > 0) {
349
+ caveats.push(`${status.index?.pendingRefs} references remain pending`);
350
+ }
351
+ if (status.index?.reindexRecommended) caveats.push("codegraph recommends reindexing");
352
+ availability = {
353
+ available: true,
354
+ stale: caveats.length > 0,
355
+ caveats,
356
+ lastIndexed: status.lastIndexed
357
+ };
358
+ }
359
+ this.statusCache.set(repository.repoRoot, {
360
+ status,
361
+ availability,
362
+ expiresAt: this.now() + this.statusTtlMs
363
+ });
364
+ return availability;
365
+ } catch (cause) {
366
+ const failure = cause;
367
+ return {
368
+ available: false,
369
+ reason: failure.kind ?? "command_failed",
370
+ stale: false,
371
+ caveats: [failure.message || "codegraph status failed"]
372
+ };
373
+ }
374
+ }
375
+ async resolveRefs(refs, options = {}) {
376
+ const normalized = refs.map(
377
+ (ref) => typeof ref === "string" ? { symbol: ref } : ref
378
+ );
379
+ const results = await Promise.all(
380
+ normalized.map(async (ref) => {
381
+ const repository2 = await this.repositoryForRef(
382
+ ref,
383
+ options.repo,
384
+ options.fallbackSpaceUid
385
+ );
386
+ const availability2 = await this.availability(repository2);
387
+ if (!availability2.available) {
388
+ return {
389
+ ref,
390
+ repository: repository2,
391
+ availability: availability2,
392
+ candidates: [],
393
+ error: availability2.reason
394
+ };
395
+ }
396
+ return {
397
+ ...await this.resolveOne(ref, repository2),
398
+ repository: repository2,
399
+ availability: availability2
400
+ };
401
+ })
402
+ );
403
+ const repositories = [
404
+ ...new Map(
405
+ results.flatMap(
406
+ (result) => result.repository ? [[result.repository.repoRoot, result.repository]] : []
407
+ )
408
+ ).values()
409
+ ];
410
+ const repository = repositories[0] ?? await this.resolveRepository(options.repo, options.fallbackSpaceUid);
411
+ if (repositories.length === 0) repositories.push(repository);
412
+ const availabilities = results.flatMap(
413
+ (result) => result.availability ? [result.availability] : []
414
+ );
415
+ const availability = availabilities.length === 0 ? await this.availability(repository) : {
416
+ available: availabilities.every((item) => item.available),
417
+ reason: availabilities.find((item) => !item.available)?.reason,
418
+ stale: availabilities.some((item) => item.stale),
419
+ caveats: [
420
+ ...new Set(availabilities.flatMap((item) => item.caveats))
421
+ ]
422
+ };
423
+ return { repository, repositories, availability, results };
424
+ }
425
+ async repositoryForRef(ref, defaultRepo, fallbackSpaceUid) {
426
+ if (ref.repo || defaultRepo) {
427
+ return this.resolveRepository(ref.repo || defaultRepo, fallbackSpaceUid);
428
+ }
429
+ if (ref.path) {
430
+ const requested = (0, import_node_path.isAbsolute)(ref.path) ? (0, import_node_path.resolve)(ref.path) : (0, import_node_path.resolve)(this.cwd, ref.path);
431
+ const absolute = await (0, import_promises.realpath)(requested).catch(() => requested);
432
+ const configured = await this.resolveRepositories(fallbackSpaceUid);
433
+ const defining = [...configured].sort((a, b) => b.repoRoot.length - a.repoRoot.length).find((candidate) => pathContains(candidate.repoRoot, absolute));
434
+ if (defining) {
435
+ return this.env.MINDGRAPH_REPO_ID && pathContains(defining.repoRoot, this.cwd) ? this.resolveRepositoryIdentity(
436
+ defining.repoRoot,
437
+ this.env.MINDGRAPH_REPO_ID,
438
+ defining.spaceUid
439
+ ) : defining;
440
+ }
441
+ const gitRoot = await this.gitRoot(absolute);
442
+ if (gitRoot) {
443
+ return this.resolveRepositoryIdentity(
444
+ gitRoot,
445
+ this.env.MINDGRAPH_REPO_ID,
446
+ this.env.MINDGRAPH_CODE_SPACE_UID || fallbackSpaceUid
447
+ );
448
+ }
449
+ }
450
+ return this.resolveRepository(void 0, fallbackSpaceUid);
451
+ }
452
+ async expand(resolved, limit = 20) {
453
+ const repository = {
454
+ repoId: resolved.repoId,
455
+ repoRoot: resolved.repoRoot
456
+ };
457
+ const availability = await this.availability(repository);
458
+ if (!availability.available) {
459
+ return { availability, callers: [], callees: [], truncated: false };
460
+ }
461
+ const cap = Math.min(Math.max(limit, 1), 20);
462
+ const [callers, callees] = await Promise.all([
463
+ this.related("callers", resolved, cap + 1),
464
+ this.related("callees", resolved, cap + 1)
465
+ ]);
466
+ return {
467
+ availability,
468
+ callers: callers.slice(0, cap),
469
+ callees: callees.slice(0, cap),
470
+ truncated: callers.length > cap || callees.length > cap
471
+ };
472
+ }
473
+ async affected(resolved, limit = 50) {
474
+ const repository = {
475
+ repoId: resolved.repoId,
476
+ repoRoot: resolved.repoRoot
477
+ };
478
+ const availability = await this.availability(repository);
479
+ if (!availability.available) {
480
+ return { availability, affected: [], truncated: false };
481
+ }
482
+ const cap = Math.min(Math.max(limit, 1), 50);
483
+ const raw = await this.runJson([
484
+ "impact",
485
+ "-p",
486
+ resolved.repoRoot,
487
+ "-j",
488
+ "-d",
489
+ "2",
490
+ resolved.qualifiedName
491
+ ]);
492
+ const refs = (raw.affected ?? []).map((node) => ({
493
+ path: node.filePath,
494
+ line: node.startLine,
495
+ symbol: node.qualifiedName ?? node.name,
496
+ kind: node.kind
497
+ }));
498
+ const resolvedRefs = await this.resolveRelatedRefs(refs.slice(0, cap + 1), repository);
499
+ return {
500
+ availability,
501
+ affected: resolvedRefs.slice(0, cap),
502
+ truncated: refs.length > cap
503
+ };
504
+ }
505
+ configuredRepositories() {
506
+ const configured = [];
507
+ if (this.workspaceFile && (0, import_node_fs.existsSync)(this.workspaceFile)) {
508
+ try {
509
+ const parsed = JSON.parse(
510
+ (0, import_node_fs.readFileSync)(this.workspaceFile, "utf8")
511
+ );
512
+ if (parsed.v === 1 && Array.isArray(parsed.repositories)) {
513
+ const configDirectory = (0, import_node_path.dirname)(this.workspaceFile);
514
+ const base = (0, import_node_path.basename)(configDirectory) === ".mindgraph" ? (0, import_node_path.dirname)(configDirectory) : configDirectory;
515
+ for (const repository of parsed.repositories) {
516
+ if (!repository || typeof repository.root !== "string") continue;
517
+ configured.push({
518
+ repoId: typeof repository.repo_id === "string" ? repository.repo_id : void 0,
519
+ repoRoot: (0, import_node_path.resolve)(base, repository.root),
520
+ spaceUid: typeof repository.space_uid === "string" ? repository.space_uid : void 0
521
+ });
522
+ }
523
+ }
524
+ } catch {
525
+ }
526
+ }
527
+ const raw = this.env.MINDGRAPH_CODE_REPOS;
528
+ if (raw) {
529
+ try {
530
+ const parsed = JSON.parse(raw);
531
+ for (const [repoId, config] of Object.entries(parsed)) {
532
+ configured.push({
533
+ repoId,
534
+ repoRoot: (0, import_node_path.resolve)(
535
+ this.cwd,
536
+ typeof config === "string" ? config : config.root
537
+ ),
538
+ spaceUid: typeof config === "string" ? void 0 : config.space_uid
539
+ });
540
+ }
541
+ } catch {
542
+ }
543
+ }
544
+ return [
545
+ ...new Map(
546
+ configured.map((repository) => [repository.repoRoot, repository])
547
+ ).values()
548
+ ];
549
+ }
550
+ async resolveOne(ref, repository) {
551
+ const search = ref.symbol || ref.path;
552
+ if (!search || ref.line !== void 0 && (!Number.isInteger(ref.line) || ref.line < 1)) {
553
+ return { ref, candidates: [], error: "invalid_ref" };
554
+ }
555
+ try {
556
+ const args = ["query", "-p", repository.repoRoot, "-j", "-l", "50"];
557
+ if (ref.kind) args.push("-k", ref.kind);
558
+ args.push(search);
559
+ const hits = await this.runJson(args);
560
+ let candidates = hits.map(asNode).map(toCandidate).filter((item) => item !== null);
561
+ if (ref.path) {
562
+ const absolutePath = (0, import_node_path.isAbsolute)(ref.path) ? await (0, import_promises.realpath)(ref.path).catch(() => ref.path) : void 0;
563
+ const wanted = normalizePath(
564
+ absolutePath ? (0, import_node_path.relative)(repository.repoRoot, absolutePath) : ref.path
565
+ );
566
+ candidates = candidates.filter((candidate) => candidate.path === wanted);
567
+ }
568
+ if (ref.language) {
569
+ candidates = candidates.filter(
570
+ (candidate) => candidate.language.toLowerCase() === ref.language?.toLowerCase()
571
+ );
572
+ }
573
+ if (ref.kind) {
574
+ candidates = candidates.filter(
575
+ (candidate) => candidate.kind.toLowerCase() === ref.kind?.toLowerCase()
576
+ );
577
+ }
578
+ if (ref.symbol) {
579
+ const exact = candidates.filter((candidate) => {
580
+ const tail = candidate.qualifiedName.split(/::|\.|#/).at(-1);
581
+ return candidate.qualifiedName === ref.symbol || tail === ref.symbol;
582
+ });
583
+ if (exact.length > 0) candidates = exact;
584
+ }
585
+ if (ref.signature) {
586
+ const signature = normalizeSignature(ref.signature);
587
+ candidates = candidates.filter(
588
+ (candidate) => candidate.signature !== null && normalizeSignature(candidate.signature) === signature
589
+ );
590
+ }
591
+ if (ref.line !== void 0) {
592
+ candidates = candidates.filter(
593
+ (candidate) => candidate.startLine <= ref.line && candidate.endLine >= ref.line
594
+ );
595
+ if (candidates.length > 1) {
596
+ const narrowest = Math.min(
597
+ ...candidates.map((candidate) => candidate.endLine - candidate.startLine)
598
+ );
599
+ const narrowed = candidates.filter(
600
+ (candidate) => candidate.endLine - candidate.startLine === narrowest
601
+ );
602
+ if (narrowed.length === 1) candidates = narrowed;
603
+ }
604
+ }
605
+ if (candidates.length !== 1) {
606
+ return {
607
+ ref,
608
+ candidates,
609
+ error: candidates.length === 0 ? "not_found" : "ambiguous"
610
+ };
611
+ }
612
+ return {
613
+ ref,
614
+ candidates,
615
+ resolved: {
616
+ repoId: repository.repoId,
617
+ repoRoot: repository.repoRoot,
618
+ ...candidates[0]
619
+ }
620
+ };
621
+ } catch (cause) {
622
+ const failure = cause;
623
+ return {
624
+ ref,
625
+ candidates: [],
626
+ error: failure.kind ?? "command_failed"
627
+ };
628
+ }
629
+ }
630
+ async related(action, resolved, limit) {
631
+ const raw = await this.runJson([
632
+ action,
633
+ "-p",
634
+ resolved.repoRoot,
635
+ "-j",
636
+ "-l",
637
+ String(limit),
638
+ resolved.qualifiedName
639
+ ]);
640
+ const refs = (raw[action] ?? []).map((node) => ({
641
+ path: node.filePath,
642
+ line: node.startLine,
643
+ symbol: node.qualifiedName ?? node.name,
644
+ kind: node.kind
645
+ }));
646
+ return this.resolveRelatedRefs(refs, {
647
+ repoId: resolved.repoId,
648
+ repoRoot: resolved.repoRoot
649
+ });
650
+ }
651
+ async resolveRelatedRefs(refs, repository) {
652
+ const results = await Promise.all(refs.map((ref) => this.resolveOne(ref, repository)));
653
+ const seen = /* @__PURE__ */ new Set();
654
+ return results.flatMap((result) => result.resolved ? [result.resolved] : []).filter((result) => {
655
+ const key = `${result.path}:${result.qualifiedName}:${result.startLine}`;
656
+ if (seen.has(key)) return false;
657
+ seen.add(key);
658
+ return true;
659
+ });
660
+ }
661
+ async runJson(args) {
662
+ const candidates = [
663
+ this.env.MINDGRAPH_CODEGRAPH_BIN,
664
+ "codegraph",
665
+ (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".local", "bin", "codegraph")
666
+ ].filter((candidate, index, all) => {
667
+ return Boolean(candidate) && all.indexOf(candidate) === index;
668
+ });
669
+ let lastFailure;
670
+ for (const executable of candidates) {
671
+ try {
672
+ const stdout = await runProcess(
673
+ executable,
674
+ args,
675
+ this.timeoutMs,
676
+ this.env,
677
+ this.cwd
678
+ );
679
+ return JSON.parse(stdout);
680
+ } catch (cause) {
681
+ const failure = cause;
682
+ lastFailure = failure;
683
+ if (failure.kind !== "absent") throw failure;
684
+ }
685
+ }
686
+ throw lastFailure ?? Object.assign(new Error("codegraph executable not found"), {
687
+ kind: "absent"
688
+ });
689
+ }
690
+ };
691
+ function repositoryIdentityKey(repository) {
692
+ return { v: 1, kind: "repository", repo_id: repository.repoId };
693
+ }
694
+ function codeRefIdentityKey(ref) {
695
+ if (ref.kind === "file") {
696
+ return {
697
+ v: 1,
698
+ kind: "file",
699
+ repo_id: ref.repoId,
700
+ path: ref.path
701
+ };
702
+ }
703
+ return {
704
+ v: 1,
705
+ kind: "symbol",
706
+ repo_id: ref.repoId,
707
+ language: ref.language,
708
+ symbol_kind: ref.kind,
709
+ qualified_name: ref.qualifiedName,
710
+ disambiguator: {
711
+ signature: ref.signature ?? "",
712
+ path: ref.path,
713
+ start_line: ref.startLine,
714
+ end_line: ref.endLine
715
+ }
716
+ };
717
+ }
718
+
719
+ // src/code-tool.ts
720
+ var ok = (data) => ({
721
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
722
+ });
723
+ var err = (code, message, details) => ({
724
+ content: [
725
+ {
726
+ type: "text",
727
+ text: JSON.stringify({ error: message, code, details }, null, 2)
728
+ }
729
+ ],
730
+ isError: true
731
+ });
732
+ var CODE_TOOL = {
733
+ name: "mindgraph_code",
734
+ description: "Resolve typed code references through the local codegraph index and join them to persistent MindGraph memory/work. anchor creates exact repository/code anchors; recall reads attached graph context; expand reads callers/callees; affected reads impact for a code ref or Task/Execution. Ambiguous refs return candidates without writing.",
735
+ inputSchema: {
736
+ type: "object",
737
+ properties: {
738
+ action: {
739
+ type: "string",
740
+ enum: ["anchor", "recall", "expand", "affected"]
741
+ },
742
+ code_refs: {
743
+ type: "array",
744
+ maxItems: 50,
745
+ items: {
746
+ oneOf: [
747
+ { type: "string" },
748
+ {
749
+ type: "object",
750
+ properties: {
751
+ repo: { type: "string" },
752
+ path: { type: "string" },
753
+ line: { type: "integer", minimum: 1 },
754
+ symbol: { type: "string" },
755
+ kind: { type: "string" },
756
+ language: { type: "string" },
757
+ signature: { type: "string" }
758
+ },
759
+ additionalProperties: false
760
+ }
761
+ ]
762
+ }
763
+ },
764
+ anchor_uids: {
765
+ type: "array",
766
+ maxItems: 50,
767
+ items: { type: "string" },
768
+ description: "Already-materialized code anchor UIDs (codegraph is not required for recall)"
769
+ },
770
+ repo: {
771
+ type: "string",
772
+ description: "Configured repository id or repository root"
773
+ },
774
+ repo_space_uid: {
775
+ type: "string",
776
+ description: "Writable shared Project/repository Space for new anchors"
777
+ },
778
+ task_uid: { type: "string" },
779
+ execution_uid: { type: "string" },
780
+ limit: { type: "integer", minimum: 1, maximum: 50 },
781
+ agent_id: { type: "string" }
782
+ },
783
+ required: ["action"]
784
+ },
785
+ annotations: {
786
+ readOnlyHint: false,
787
+ destructiveHint: false,
788
+ idempotentHint: true,
789
+ openWorldHint: true
790
+ }
791
+ };
792
+ async function handleCodeTool(client2, args, adapter = new CodegraphAdapter()) {
793
+ const codeClient = client2;
794
+ const action = args.action;
795
+ const refs = Array.isArray(args.code_refs) ? args.code_refs : [];
796
+ const anchorUids = Array.isArray(args.anchor_uids) ? args.anchor_uids : [];
797
+ const agentId = typeof args.agent_id === "string" ? args.agent_id : "mcp";
798
+ const fallbackSpaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : `space:agent:${agentId}`;
799
+ const options = {
800
+ repo: typeof args.repo === "string" ? args.repo : void 0,
801
+ fallbackSpaceUid
802
+ };
803
+ const limit = typeof args.limit === "number" ? args.limit : void 0;
804
+ try {
805
+ switch (action) {
806
+ case "anchor": {
807
+ if (refs.length === 0) return err("missing_code_refs", "code_refs is required for anchor");
808
+ const resolution = await adapter.resolveRefs(refs, options);
809
+ const resolved = resolution.results.flatMap(
810
+ (result) => result.resolved && result.repository ? [{ ref: result.resolved, repository: result.repository }] : []
811
+ );
812
+ const unresolved = resolution.results.filter((result) => !result.resolved);
813
+ if (resolved.length === 0) {
814
+ return ok({ ...resolution, anchors: [], wrote: false });
815
+ }
816
+ const missingSpace = resolved.find(
817
+ ({ repository }) => typeof args.repo_space_uid !== "string" && !repository.spaceUid
818
+ );
819
+ if (missingSpace) {
820
+ return err(
821
+ "missing_repository_space",
822
+ `repo_space_uid, a workspace space_uid, or MINDGRAPH_CODE_SPACE_UID is required for ${missingSpace.repository.repoId}`
823
+ );
824
+ }
825
+ const repositoryAnchors = /* @__PURE__ */ new Map();
826
+ for (const { repository } of resolved) {
827
+ if (repositoryAnchors.has(repository.repoRoot)) continue;
828
+ const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
829
+ const anchored = await anchorRepository(
830
+ codeClient,
831
+ repository,
832
+ spaceUid,
833
+ agentId
834
+ );
835
+ repositoryAnchors.set(repository.repoRoot, {
836
+ ...anchored,
837
+ repository
838
+ });
839
+ }
840
+ const anchors = [];
841
+ for (const { ref, repository } of resolved) {
842
+ const repositoryAnchor = repositoryAnchors.get(repository.repoRoot);
843
+ if (!repositoryAnchor.uid) continue;
844
+ const spaceUid = typeof args.repo_space_uid === "string" ? args.repo_space_uid : repository.spaceUid;
845
+ const anchor = await anchorCodeRef(
846
+ codeClient,
847
+ ref,
848
+ repositoryAnchor.uid,
849
+ spaceUid,
850
+ agentId
851
+ );
852
+ anchors.push(anchor);
853
+ }
854
+ return ok({
855
+ availability: resolution.availability,
856
+ repository: repositoryAnchors.values().next().value,
857
+ repositories: [...repositoryAnchors.values()],
858
+ anchors,
859
+ unresolved,
860
+ wrote: anchors.some((anchor) => anchor.created)
861
+ });
862
+ }
863
+ case "recall": {
864
+ const materialized = new Set(anchorUids);
865
+ let resolution;
866
+ if (refs.length > 0) {
867
+ resolution = await adapter.resolveRefs(refs, options);
868
+ for (const result of resolution.results) {
869
+ if (!result.resolved) continue;
870
+ const uid = await resolveMaterializedUid(codeClient, result.resolved, agentId);
871
+ if (uid) materialized.add(uid);
872
+ }
873
+ }
874
+ if (materialized.size === 0) {
875
+ return ok({
876
+ availability: resolution?.availability,
877
+ anchors: [],
878
+ context: [],
879
+ unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
880
+ });
881
+ }
882
+ const context = await Promise.all(
883
+ [...materialized].map(async (uid) => ({
884
+ anchor_uid: uid,
885
+ graph: await codeClient.traverse({
886
+ action: "neighborhood",
887
+ start_uid: uid,
888
+ depth: 2,
889
+ max_nodes: Math.min(limit ?? 20, 20)
890
+ })
891
+ }))
892
+ );
893
+ return ok({
894
+ availability: resolution?.availability,
895
+ anchors: [...materialized],
896
+ context,
897
+ unresolved: resolution?.results.filter((result) => !result.resolved) ?? []
898
+ });
899
+ }
900
+ case "expand": {
901
+ const target = await resolveSingleTarget(
902
+ codeClient,
903
+ adapter,
904
+ refs,
905
+ anchorUids,
906
+ options
907
+ );
908
+ if ("error" in target) return target.error;
909
+ const expanded = await adapter.expand(target.ref, limit);
910
+ const joined = await joinMaterialized(
911
+ codeClient,
912
+ [...expanded.callers, ...expanded.callees],
913
+ agentId,
914
+ Math.min(limit ?? 20, 20)
915
+ );
916
+ return ok({ anchor: target.ref, ...expanded, materialized: joined });
917
+ }
918
+ case "affected": {
919
+ const targetUid = typeof args.task_uid === "string" ? args.task_uid : typeof args.execution_uid === "string" ? args.execution_uid : void 0;
920
+ let graphContext;
921
+ const graphRefs = [];
922
+ if (targetUid) {
923
+ graphContext = await codeClient.traverse({
924
+ action: "neighborhood",
925
+ start_uid: targetUid,
926
+ depth: 2,
927
+ max_nodes: 50
928
+ });
929
+ graphRefs.push(
930
+ ...await codeRefsFromGraphContext(codeClient, adapter, graphContext)
931
+ );
932
+ }
933
+ if (refs.length > 0 || anchorUids.length > 0) {
934
+ const target = await resolveSingleTarget(
935
+ codeClient,
936
+ adapter,
937
+ refs,
938
+ anchorUids,
939
+ options
940
+ );
941
+ if ("error" in target) return target.error;
942
+ graphRefs.unshift(target.ref);
943
+ }
944
+ const unique = uniqueRefs(graphRefs);
945
+ if (unique.length === 0) {
946
+ return ok({
947
+ target_uid: targetUid,
948
+ graph_context: graphContext,
949
+ affected: [],
950
+ degradation: "no materialized code anchors were attached"
951
+ });
952
+ }
953
+ const impacts = await Promise.all(
954
+ unique.map(async (ref) => ({ anchor: ref, ...await adapter.affected(ref, limit) }))
955
+ );
956
+ const structural = uniqueRefs(impacts.flatMap((impact) => impact.affected));
957
+ const joined = await joinMaterialized(
958
+ codeClient,
959
+ structural,
960
+ agentId,
961
+ Math.min(limit ?? 50, 50)
962
+ );
963
+ return ok({
964
+ target_uid: targetUid,
965
+ graph_context: graphContext,
966
+ impacts,
967
+ materialized: joined
968
+ });
969
+ }
970
+ default:
971
+ return err("unknown_action", `unknown mindgraph_code action: ${action}`);
972
+ }
973
+ } catch (cause) {
974
+ return err("code_tool_failed", errorDetail(cause));
975
+ }
976
+ }
977
+ async function attachCodeRefsToToolResult(client2, result, args, adapter) {
978
+ if (result.isError || !Array.isArray(args.code_refs) || args.code_refs.length === 0) {
979
+ return result;
980
+ }
981
+ const original = JSON.parse(result.content[0]?.text ?? "null");
982
+ const targetUids = primaryUids(original);
983
+ if (targetUids.length === 0) {
984
+ return ok({
985
+ result: original,
986
+ code_anchors: {
987
+ wrote: false,
988
+ caveat: "the write response exposed no primary UID to attach"
989
+ }
990
+ });
991
+ }
992
+ const anchorResult = await handleCodeTool(
993
+ client2,
994
+ {
995
+ action: "anchor",
996
+ code_refs: args.code_refs,
997
+ repo: args.repo,
998
+ repo_space_uid: args.repo_space_uid,
999
+ agent_id: args.agent_id
1000
+ },
1001
+ adapter
1002
+ );
1003
+ const anchors = JSON.parse(anchorResult.content[0]?.text ?? "null");
1004
+ if (!anchorResult.isError) {
1005
+ const codeClient = client2;
1006
+ const anchorUids = (anchors.anchors ?? []).flatMap(
1007
+ (anchor) => anchor.uid ? [anchor.uid] : []
1008
+ );
1009
+ for (const targetUid of targetUids) {
1010
+ for (const anchorUid of anchorUids) {
1011
+ await codeClient.entity({
1012
+ action: "relate",
1013
+ source_uid: targetUid,
1014
+ target_uid: anchorUid,
1015
+ edge_type: args.action === "lesson" ? "ABOUT" : "RELEVANT_TO",
1016
+ agent_id: args.agent_id
1017
+ });
1018
+ }
1019
+ }
1020
+ }
1021
+ return ok({ result: original, code_anchors: anchors });
1022
+ }
1023
+ async function anchorRepository(client2, repository, spaceUid, agentId) {
1024
+ return client2.entity({
1025
+ action: "create",
1026
+ label: repository.repoId,
1027
+ props: {
1028
+ entity_type: "repository",
1029
+ canonical_name: repository.repoId,
1030
+ identifiers: { repo_id: repository.repoId }
1031
+ },
1032
+ identity: {
1033
+ namespace: "external.code",
1034
+ key_version: 1,
1035
+ key: repositoryIdentityKey(repository)
1036
+ },
1037
+ identity_space_uid: spaceUid,
1038
+ agent_id: agentId
1039
+ });
1040
+ }
1041
+ async function anchorCodeRef(client2, ref, repositoryUid, spaceUid, agentId) {
1042
+ const response = await client2.entity({
1043
+ action: "create",
1044
+ label: ref.qualifiedName,
1045
+ props: {
1046
+ entity_type: ref.kind === "file" ? "code_file" : "code_symbol",
1047
+ canonical_name: ref.qualifiedName,
1048
+ identifiers: {
1049
+ repo_id: ref.repoId,
1050
+ path: ref.path,
1051
+ qualified_name: ref.qualifiedName
1052
+ },
1053
+ attributes: { code_ref: storedCodeRef(ref) }
1054
+ },
1055
+ identity: {
1056
+ namespace: "external.code",
1057
+ key_version: 1,
1058
+ key: codeRefIdentityKey(ref)
1059
+ },
1060
+ identity_space_uid: spaceUid,
1061
+ agent_id: agentId
1062
+ });
1063
+ if (response.uid) {
1064
+ await client2.entity({
1065
+ action: "relate",
1066
+ source_uid: response.uid,
1067
+ target_uid: repositoryUid,
1068
+ edge_type: "PART_OF",
1069
+ agent_id: agentId
1070
+ });
1071
+ }
1072
+ return { ...response, ref };
1073
+ }
1074
+ async function resolveMaterializedUid(client2, ref, agentId) {
1075
+ const response = await client2.entity({
1076
+ action: "resolve_identity",
1077
+ identity: {
1078
+ namespace: "external.code",
1079
+ key_version: 1,
1080
+ key: codeRefIdentityKey(ref)
1081
+ },
1082
+ agent_id: agentId
1083
+ });
1084
+ return response.status === "existing" ? response.uid : void 0;
1085
+ }
1086
+ async function codeRefFromAnchor(client2, adapter, uid) {
1087
+ const node = await client2.getNode(uid);
1088
+ const attributes = node.props?.attributes;
1089
+ if (!attributes || typeof attributes !== "object") return void 0;
1090
+ const codeRef = attributes.code_ref;
1091
+ if (!isStoredCodeRef(codeRef)) return void 0;
1092
+ const repository = await adapter.resolveRepository(codeRef.repoId);
1093
+ return { ...codeRef, repoRoot: repository.repoRoot };
1094
+ }
1095
+ async function resolveSingleTarget(client2, adapter, refs, anchorUids, options) {
1096
+ if (refs.length > 1 || anchorUids.length > 1) {
1097
+ return { error: err("ambiguous_target", "expand/affected accepts exactly one code target") };
1098
+ }
1099
+ if (anchorUids.length === 1) {
1100
+ const ref = await codeRefFromAnchor(client2, adapter, anchorUids[0]);
1101
+ return ref ? { ref } : { error: err("invalid_anchor", "anchor UID does not contain a typed code_ref") };
1102
+ }
1103
+ if (refs.length !== 1) {
1104
+ return { error: err("missing_code_ref", "one code_ref or anchor_uid is required") };
1105
+ }
1106
+ const resolution = await adapter.resolveRefs(refs, options);
1107
+ const result = resolution.results[0];
1108
+ if (!result.resolved) {
1109
+ return {
1110
+ error: ok({
1111
+ availability: resolution.availability,
1112
+ result,
1113
+ wrote: false
1114
+ })
1115
+ };
1116
+ }
1117
+ return { ref: result.resolved };
1118
+ }
1119
+ async function joinMaterialized(client2, refs, agentId, limit) {
1120
+ const joined = [];
1121
+ for (const ref of uniqueRefs(refs).slice(0, limit)) {
1122
+ const uid = await resolveMaterializedUid(client2, ref, agentId);
1123
+ if (!uid) continue;
1124
+ joined.push({
1125
+ ref,
1126
+ anchor_uid: uid,
1127
+ graph: await client2.traverse({
1128
+ action: "neighborhood",
1129
+ start_uid: uid,
1130
+ depth: 2,
1131
+ max_nodes: 20
1132
+ })
1133
+ });
1134
+ }
1135
+ return joined;
1136
+ }
1137
+ async function codeRefsFromGraphContext(client2, adapter, context) {
1138
+ const uids = /* @__PURE__ */ new Set();
1139
+ collectUids(context, uids);
1140
+ if (uids.size === 0) return [];
1141
+ const nodes = client2.getNodesBatch ? await client2.getNodesBatch([...uids]) : await Promise.all([...uids].map((uid) => client2.getNode(uid).catch(() => void 0)));
1142
+ const stored = nodes.flatMap((node) => {
1143
+ if (!node) return [];
1144
+ const attributes = node.props?.attributes;
1145
+ if (!attributes || typeof attributes !== "object") return [];
1146
+ const codeRef = attributes.code_ref;
1147
+ return isStoredCodeRef(codeRef) ? [codeRef] : [];
1148
+ });
1149
+ return Promise.all(
1150
+ stored.map(async (ref) => {
1151
+ const repository = await adapter.resolveRepository(ref.repoId);
1152
+ return { ...ref, repoRoot: repository.repoRoot };
1153
+ })
1154
+ );
1155
+ }
1156
+ function collectUids(value, uids) {
1157
+ if (Array.isArray(value)) {
1158
+ value.forEach((item) => collectUids(item, uids));
1159
+ return;
1160
+ }
1161
+ if (!value || typeof value !== "object") return;
1162
+ for (const [key, child] of Object.entries(value)) {
1163
+ if (typeof child === "string" && ["uid", "node_uid", "neighbor_uid", "from_uid", "to_uid"].includes(key)) {
1164
+ uids.add(child);
1165
+ } else {
1166
+ collectUids(child, uids);
1167
+ }
1168
+ }
1169
+ }
1170
+ function isStoredCodeRef(value) {
1171
+ if (!value || typeof value !== "object") return false;
1172
+ const ref = value;
1173
+ return typeof ref.repoId === "string" && typeof ref.path === "string" && typeof ref.language === "string" && typeof ref.kind === "string" && typeof ref.qualifiedName === "string" && (typeof ref.signature === "string" || ref.signature === null) && typeof ref.startLine === "number" && typeof ref.endLine === "number";
1174
+ }
1175
+ function storedCodeRef(ref) {
1176
+ const { repoRoot: _localOnly, ...stored } = ref;
1177
+ return stored;
1178
+ }
1179
+ function uniqueRefs(refs) {
1180
+ const seen = /* @__PURE__ */ new Set();
1181
+ return refs.filter((ref) => {
1182
+ const key = `${ref.repoId}:${ref.path}:${ref.qualifiedName}:${ref.signature ?? ""}`;
1183
+ if (seen.has(key)) return false;
1184
+ seen.add(key);
1185
+ return true;
1186
+ });
1187
+ }
1188
+ function primaryUids(value) {
1189
+ if (!value || typeof value !== "object") return [];
1190
+ const object = value;
1191
+ const keys = [
1192
+ "uid",
1193
+ "claim_uid",
1194
+ "goal_uid",
1195
+ "project_uid",
1196
+ "milestone_uid",
1197
+ "decision_uid",
1198
+ "task_uid",
1199
+ "plan_uid",
1200
+ "step_uid",
1201
+ "execution_uid",
1202
+ "lesson_uid"
1203
+ ];
1204
+ return [
1205
+ ...new Set(
1206
+ keys.flatMap((key) => typeof object[key] === "string" ? [object[key]] : [])
1207
+ )
1208
+ ];
1209
+ }
1210
+
1211
+ // src/sync-tool.ts
1212
+ var import_node_crypto2 = __toESM(require("crypto"));
1213
+ var import_node_fs2 = __toESM(require("fs"));
1214
+ var import_node_path2 = __toESM(require("path"));
1215
+ var ok2 = (data) => ({
1216
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
1217
+ });
1218
+ var err2 = (code, message) => ({
1219
+ content: [{ type: "text", text: JSON.stringify({ code, error: message }) }],
1220
+ isError: true
1221
+ });
1222
+ var SYNC_TOOL = {
1223
+ name: "mindgraph_sync",
1224
+ description: "Transactional one-way project memory-file sync. scan/status are reads; begin/record/finalize/abandon are writes. Discovery and hashing are automatic; semantic assertions are deliberately supplied through record. This never writes graph state back to files.",
1225
+ annotations: {
1226
+ readOnlyHint: false,
1227
+ destructiveHint: false,
1228
+ idempotentHint: true,
1229
+ openWorldHint: true
1230
+ },
1231
+ inputSchema: {
1232
+ type: "object",
1233
+ properties: {
1234
+ action: {
1235
+ type: "string",
1236
+ enum: ["scan", "begin", "record", "finalize", "status", "abandon"]
1237
+ },
1238
+ paths: { type: "array", items: { type: "string" } },
1239
+ workspace: {
1240
+ type: "boolean",
1241
+ description: "For scan only: fan out across repositories explicitly listed in .mindgraph/workspace.json"
1242
+ },
1243
+ repo: {
1244
+ type: "string",
1245
+ description: "Configured repository id, name, or root"
1246
+ },
1247
+ logical_path: { type: "string" },
1248
+ content: { type: "string" },
1249
+ content_hash: { type: "string" },
1250
+ source_uid: { type: "string" },
1251
+ execution_uid: { type: "string" },
1252
+ assertion_fingerprint: { type: "string" },
1253
+ planned_fingerprints: { type: "array", items: { type: "string" } },
1254
+ current_fingerprints: { type: "array", items: { type: "string" } },
1255
+ source_selector: { type: "object" },
1256
+ capture_type: {
1257
+ type: "string",
1258
+ enum: ["lesson", "journal", "claim", "decision", "risk"]
1259
+ },
1260
+ label: { type: "string" },
1261
+ summary: { type: "string" },
1262
+ props: { type: "object" },
1263
+ expected_execution_version: { type: "integer", minimum: 1 },
1264
+ baseline_version: { type: "integer", minimum: 1 },
1265
+ repo_space_uid: { type: "string" },
1266
+ repo_id: { type: "string" },
1267
+ provider: { type: "string", enum: ["claude_project", "explicit"] },
1268
+ file_present: { type: "boolean" },
1269
+ agent_id: { type: "string" },
1270
+ invocation_context: {
1271
+ type: "object",
1272
+ description: "Adapter-owned; hooks replace forged or absent values.",
1273
+ properties: {
1274
+ harness: { type: "string" },
1275
+ harnessSessionId: { type: "string" },
1276
+ harnessTurnId: { type: "string" },
1277
+ cwd: { type: "string" },
1278
+ repoId: { type: "string" },
1279
+ branch: { type: "string" },
1280
+ commit: { type: "string" },
1281
+ worktreeState: { type: "string" },
1282
+ model: { type: "string" },
1283
+ injectedBy: { type: "string" }
1284
+ }
1285
+ }
1286
+ },
1287
+ required: ["action"]
1288
+ }
1289
+ };
1290
+ function safePath(root, candidate) {
1291
+ const absolute = import_node_path2.default.resolve(root, candidate);
1292
+ const relative2 = import_node_path2.default.relative(root, absolute);
1293
+ if (relative2.startsWith("..") || import_node_path2.default.isAbsolute(relative2)) {
1294
+ throw new Error(`path escapes repository root: ${candidate}`);
1295
+ }
1296
+ return absolute;
1297
+ }
1298
+ function markdownFiles(target) {
1299
+ if (!import_node_fs2.default.existsSync(target)) return [];
1300
+ const stat = import_node_fs2.default.statSync(target);
1301
+ if (stat.isFile()) return target.endsWith(".md") ? [target] : [];
1302
+ if (!stat.isDirectory()) return [];
1303
+ return import_node_fs2.default.readdirSync(target, { withFileTypes: true }).flatMap((entry) => markdownFiles(import_node_path2.default.join(target, entry.name)));
1304
+ }
1305
+ function fileDescriptor(root, absolute) {
1306
+ const content = import_node_fs2.default.readFileSync(absolute, "utf8");
1307
+ return {
1308
+ logical_path: import_node_path2.default.relative(root, absolute).split(import_node_path2.default.sep).join("/"),
1309
+ content_hash: import_node_crypto2.default.createHash("sha256").update(content).digest("hex"),
1310
+ bytes: Buffer.byteLength(content),
1311
+ content
1312
+ };
1313
+ }
1314
+ async function handleSyncTool(client2, args) {
1315
+ try {
1316
+ const action = String(args.action || "");
1317
+ const context = args.invocation_context || {};
1318
+ const adapter = new CodegraphAdapter({
1319
+ cwd: context.cwd || process.cwd()
1320
+ });
1321
+ const requestedRepo = typeof args.repo === "string" ? args.repo : typeof args.repo_id === "string" ? args.repo_id : context.repoId;
1322
+ const repository = await adapter.resolveRepository(requestedRepo);
1323
+ const root = repository.repoRoot;
1324
+ const repoId = repository.repoId;
1325
+ const provider = String(args.provider || "claude_project");
1326
+ const remote = client2;
1327
+ if (action === "scan") {
1328
+ const repositories = args.workspace === true ? await adapter.resolveRepositories() : [repository];
1329
+ const requested = Array.isArray(args.paths) && args.paths.length > 0 ? args.paths.map(String) : [".claude/agent-memory", "memory"];
1330
+ const scans = [];
1331
+ for (const selected of repositories) {
1332
+ scans.push(
1333
+ await scanRepository(
1334
+ remote,
1335
+ selected,
1336
+ requested,
1337
+ provider,
1338
+ args.agent_id
1339
+ )
1340
+ );
1341
+ }
1342
+ if (args.workspace === true) {
1343
+ return ok2({
1344
+ provider,
1345
+ workspace: true,
1346
+ repositories: scans,
1347
+ one_way: "files_to_graph"
1348
+ });
1349
+ }
1350
+ return ok2(scans[0]);
1351
+ }
1352
+ const request = {
1353
+ ...args,
1354
+ provider,
1355
+ repo_id: repoId
1356
+ };
1357
+ delete request.invocation_context;
1358
+ delete request.paths;
1359
+ delete request.repo;
1360
+ delete request.workspace;
1361
+ if (action === "begin" && !request.content) {
1362
+ if (!request.logical_path) {
1363
+ return err2("missing_field", "logical_path is required for begin");
1364
+ }
1365
+ const file = fileDescriptor(
1366
+ root,
1367
+ safePath(root, String(request.logical_path))
1368
+ );
1369
+ request.content = file.content;
1370
+ request.content_hash ||= file.content_hash;
1371
+ }
1372
+ if (action === "status" && request.logical_path && request.file_present !== false) {
1373
+ const absolute = safePath(root, String(request.logical_path));
1374
+ request.file_present = import_node_fs2.default.existsSync(absolute);
1375
+ if (request.file_present && !request.content_hash) {
1376
+ request.content_hash = fileDescriptor(root, absolute).content_hash;
1377
+ }
1378
+ }
1379
+ return ok2(await remote.memorySync(request));
1380
+ } catch (error) {
1381
+ return err2("sync_failed", errorDetail(error));
1382
+ }
1383
+ }
1384
+ async function scanRepository(remote, repository, requested, provider, agentId) {
1385
+ const files = [
1386
+ ...new Set(
1387
+ requested.flatMap(
1388
+ (candidate) => markdownFiles(safePath(repository.repoRoot, candidate))
1389
+ )
1390
+ )
1391
+ ].sort();
1392
+ const results = [];
1393
+ for (const absolute of files) {
1394
+ const file = fileDescriptor(repository.repoRoot, absolute);
1395
+ const status = await remote.memorySync({
1396
+ action: "scan",
1397
+ provider,
1398
+ repo_id: repository.repoId,
1399
+ logical_path: file.logical_path,
1400
+ content_hash: file.content_hash,
1401
+ file_present: true,
1402
+ agent_id: agentId
1403
+ });
1404
+ results.push({
1405
+ logical_path: file.logical_path,
1406
+ content_hash: file.content_hash,
1407
+ bytes: file.bytes,
1408
+ status
1409
+ });
1410
+ }
1411
+ return {
1412
+ repo_id: repository.repoId,
1413
+ root: ".",
1414
+ files: results
1415
+ };
1416
+ }
8
1417
 
9
1418
  // src/tools.ts
10
1419
  var TOOLS = [
11
1420
  {
12
1421
  name: "mindgraph_capture",
13
- description: "Capture knowledge into the graph. Use 'entity' for people/orgs/places/events/nations/concepts (auto-deduplicates \u2014 safe to call even if already exists), 'observation' for factual statements, 'source' for documents/URLs, 'snippet' for quotes from a source, 'concept' for abstract ideas. Use 'journal' for quick personal notes, preferences, reflections, moods \u2014 anything subjective or informal. Prefer 'entity'/'observation' for objective facts, 'journal' for personal notes.",
1422
+ description: "Capture knowledge into the graph. Use 'entity' for people/orgs/places/events/nations/concepts (auto-deduplicates \u2014 safe to call even if already exists), 'observation' for factual statements, 'source' for documents/URLs, 'snippet' for quotes from a source, and 'concept' for abstract ideas. Use 'journal' for quick personal notes and 'lesson' for a durable learning attributable to a session or source nodes. Prefer 'entity'/'observation' for objective facts, 'journal' for informal notes, and 'lesson' only for reusable knowledge.",
14
1423
  inputSchema: {
15
1424
  type: "object",
16
1425
  properties: {
17
1426
  action: {
18
1427
  type: "string",
19
- enum: ["entity", "observation", "source", "snippet", "concept", "journal"],
1428
+ enum: [
1429
+ "entity",
1430
+ "observation",
1431
+ "source",
1432
+ "snippet",
1433
+ "concept",
1434
+ "journal",
1435
+ "lesson"
1436
+ ],
20
1437
  description: "Type of knowledge to capture"
21
1438
  },
22
1439
  label: {
@@ -31,6 +1448,31 @@ var TOOLS = [
31
1448
  type: "string",
32
1449
  description: "Journal content/body text (for action=journal)"
33
1450
  },
1451
+ session_uid: {
1452
+ type: "string",
1453
+ description: "Session UID that produced a lesson (for action=lesson)"
1454
+ },
1455
+ work_uid: {
1456
+ type: "string",
1457
+ description: "Durable Task/work UID this capture is relevant to"
1458
+ },
1459
+ execution_uid: {
1460
+ type: "string",
1461
+ description: "Material Execution that produced the lesson"
1462
+ },
1463
+ idempotency_key: {
1464
+ type: "string",
1465
+ description: "Stable retry key for an intentional capture"
1466
+ },
1467
+ supersedes_uid: {
1468
+ type: "string",
1469
+ description: "Earlier capture corrected or superseded by this one"
1470
+ },
1471
+ summarizes_uids: {
1472
+ type: "array",
1473
+ items: { type: "string" },
1474
+ description: "Source node UIDs the lesson was learned from (for action=lesson)"
1475
+ },
34
1476
  entity_type: {
35
1477
  type: "string",
36
1478
  enum: ["person", "organization", "place", "event", "nation", "concept"],
@@ -65,6 +1507,32 @@ var TOOLS = [
65
1507
  type: "object",
66
1508
  description: "Type-specific properties (e.g. birth_date for person, coordinates for place)"
67
1509
  },
1510
+ code_refs: {
1511
+ type: "array",
1512
+ items: {
1513
+ oneOf: [
1514
+ { type: "string" },
1515
+ {
1516
+ type: "object",
1517
+ properties: {
1518
+ repo: { type: "string" },
1519
+ path: { type: "string" },
1520
+ line: { type: "integer", minimum: 1 },
1521
+ symbol: { type: "string" },
1522
+ kind: { type: "string" },
1523
+ language: { type: "string" },
1524
+ signature: { type: "string" }
1525
+ }
1526
+ }
1527
+ ]
1528
+ },
1529
+ description: "Typed code targets to anchor and attach to the captured node"
1530
+ },
1531
+ repo: { type: "string", description: "Configured repository id or root" },
1532
+ repo_space_uid: {
1533
+ type: "string",
1534
+ description: "Writable shared repository/Project Space for new code anchors"
1535
+ },
68
1536
  agent_id: {
69
1537
  type: "string",
70
1538
  description: "Agent identity"
@@ -238,6 +1706,16 @@ var TOOLS = [
238
1706
  type: "object",
239
1707
  description: "Type-specific properties (e.g. status, priority, deadline, horizon for goals)"
240
1708
  },
1709
+ code_refs: {
1710
+ type: "array",
1711
+ items: { oneOf: [{ type: "string" }, { type: "object" }] },
1712
+ description: "Typed code targets to anchor and attach to the created commitment"
1713
+ },
1714
+ repo: { type: "string", description: "Configured repository id or root" },
1715
+ repo_space_uid: {
1716
+ type: "string",
1717
+ description: "Writable shared repository/Project Space for new code anchors"
1718
+ },
241
1719
  agent_id: {
242
1720
  type: "string",
243
1721
  description: "Agent identity"
@@ -248,7 +1726,7 @@ var TOOLS = [
248
1726
  },
249
1727
  {
250
1728
  name: "mindgraph_plan",
251
- description: "Agent-level task management, governance, and procedural knowledge. Use 'create_plan'/'create_task'/'add_step' for task breakdowns, 'update_status' for progress, 'get_plan' to review. Use 'create_flow'/'add_procedure_step'/'add_affordance'/'add_control' for workflows and procedures. Use 'assess_risk'/'get_assessments' for risk analysis. Use 'get_pending' to read the governance approval queue \u2014 approvals are granted by a person in the MindGraph dashboard, never from here, so wait for one rather than trying to clear it. Prefer mindgraph_commit for user goals/projects; use this for agent-managed execution.",
1729
+ description: "Authoritative durable engineering work and execution evidence. Use create_task/create_plan/add_step for work that must survive sessions; resume_work for the deterministic bounded brief; claim_task + heartbeat for the fenced lease; and start_iteration/checkpoint_iteration/block_task/complete_task/abandon_iteration for idempotent material attempts. Every composite write needs task version, Session, lease epoch, and an idempotency key. Use the harness-native todo list only for local coordination; never maintain the same authoritative Task in both systems.",
252
1730
  inputSchema: {
253
1731
  type: "object",
254
1732
  properties: {
@@ -260,9 +1738,19 @@ var TOOLS = [
260
1738
  "add_step",
261
1739
  "update_status",
262
1740
  "get_plan",
1741
+ "resume_work",
1742
+ "claim_task",
1743
+ "heartbeat",
1744
+ "start_iteration",
1745
+ "checkpoint_iteration",
1746
+ "block_task",
1747
+ "complete_task",
1748
+ "abandon_iteration",
263
1749
  "start_execution",
264
1750
  "complete_execution",
265
1751
  "fail_execution",
1752
+ "register_agent",
1753
+ "get_executions",
266
1754
  // C33: governance WRITES are deliberately not exposed here.
267
1755
  // `create_policy` let a model author the rules it is judged by;
268
1756
  // `request_approval` + `resolve_approval` let it raise and then
@@ -290,30 +1778,189 @@ var TOOLS = [
290
1778
  },
291
1779
  plan_uid: {
292
1780
  type: "string",
293
- description: "Plan UID (for add_step, get_plan)"
1781
+ description: "Plan UID (for create_plan execution link, add_step, get_plan)"
294
1782
  },
295
1783
  task_uid: {
296
1784
  type: "string",
297
- description: "Task/step UID (for update_status, execution actions)"
1785
+ description: "Task UID (for create_plan and graph-managed work actions)"
1786
+ },
1787
+ step_uid: {
1788
+ type: "string",
1789
+ description: "PlanStep UID for an iteration/checkpoint"
1790
+ },
1791
+ session_uid: {
1792
+ type: "string",
1793
+ description: "Durable Session UID that owns the task lease"
1794
+ },
1795
+ goal_uid: {
1796
+ type: "string",
1797
+ description: "Goal UID targeted by a task or plan"
298
1798
  },
299
1799
  target_uid: {
300
1800
  type: "string",
301
- description: "Parent flow/step UID or target node (for procedure/risk actions)"
1801
+ description: "Task/plan/step UID for update_status, or parent/target node for procedure and risk actions"
1802
+ },
1803
+ execution_uid: {
1804
+ type: "string",
1805
+ description: "Execution UID (required for complete_execution/fail_execution)"
1806
+ },
1807
+ executor_uid: {
1808
+ type: "string",
1809
+ description: "Agent node UID that executed the work"
1810
+ },
1811
+ affordance_uid: {
1812
+ type: "string",
1813
+ description: "Affordance invoked by start_execution"
1814
+ },
1815
+ produces_node_uid: {
1816
+ type: "string",
1817
+ description: "Node produced by a completed execution"
1818
+ },
1819
+ filter_plan_uid: {
1820
+ type: "string",
1821
+ description: "Restrict get_executions to one plan"
1822
+ },
1823
+ depends_on_uids: {
1824
+ type: "array",
1825
+ items: { type: "string" },
1826
+ description: "Plan-step UIDs that an added step depends on"
1827
+ },
1828
+ related_uids: {
1829
+ type: "array",
1830
+ items: { type: "string" },
1831
+ description: "Target node UIDs to link to created work or an execution"
302
1832
  },
303
1833
  status: {
304
1834
  type: "string",
305
1835
  description: "New status value (for update_status)"
306
1836
  },
1837
+ task_status: {
1838
+ type: "string",
1839
+ description: "Task status requested by a checkpoint or abandon action"
1840
+ },
1841
+ step_status: {
1842
+ type: "string",
1843
+ description: "PlanStep status requested by a checkpoint"
1844
+ },
1845
+ execution_status: {
1846
+ type: "string",
1847
+ enum: ["completed", "failed", "abandoned"],
1848
+ description: "Terminal Execution status for checkpoint_iteration"
1849
+ },
1850
+ expected_version: {
1851
+ type: "number",
1852
+ description: "Current Task node version used as the optimistic fence"
1853
+ },
1854
+ lease_epoch: {
1855
+ type: "number",
1856
+ description: "Current monotonic task-lease epoch"
1857
+ },
1858
+ lease_ttl_secs: {
1859
+ type: "number",
1860
+ minimum: 1,
1861
+ description: "Requested server-time lease lifetime (default 300s)"
1862
+ },
1863
+ idempotency_key: {
1864
+ type: "string",
1865
+ description: "Caller-stable key required for every composite work mutation"
1866
+ },
1867
+ allow_takeover: {
1868
+ type: "boolean",
1869
+ description: "Governed claim override for a live lease owned by another agent"
1870
+ },
1871
+ release_lease: {
1872
+ type: "boolean",
1873
+ description: "Explicitly release or retain the lease after block/abandon/checkpoint"
1874
+ },
1875
+ override_reason: {
1876
+ type: "string",
1877
+ description: "Explicit completion reason when no terminal Execution evidence exists"
1878
+ },
1879
+ scope_uids: {
1880
+ type: "array",
1881
+ items: { type: "string" },
1882
+ description: "Ordinary target UIDs that bound deterministic resume selection"
1883
+ },
1884
+ limit: {
1885
+ type: "number",
1886
+ minimum: 1,
1887
+ maximum: 1,
1888
+ description: "Resume returns one authoritative Task"
1889
+ },
1890
+ input_snapshot: {
1891
+ type: "object",
1892
+ description: "Structured inputs captured when an execution starts"
1893
+ },
1894
+ output_snapshot: {
1895
+ type: "object",
1896
+ description: "Structured outputs captured when an execution completes or fails"
1897
+ },
1898
+ outcome: {
1899
+ type: "string",
1900
+ description: "Execution outcome"
1901
+ },
1902
+ error: {
1903
+ type: "string",
1904
+ description: "Execution error detail (for fail_execution)"
1905
+ },
1906
+ side_effects: {
1907
+ type: "array",
1908
+ items: { type: "string" },
1909
+ description: "Observable side effects of the execution"
1910
+ },
1911
+ next_action: {
1912
+ type: "string",
1913
+ description: "Recommended next action retained on terminal Execution evidence"
1914
+ },
1915
+ checkpoint_summary: {
1916
+ type: "string",
1917
+ description: "Bounded material-attempt checkpoint summary"
1918
+ },
1919
+ test_summary: {
1920
+ type: "string",
1921
+ description: "Test commands/results retained on the Execution"
1922
+ },
1923
+ produces_node_uids: {
1924
+ type: "array",
1925
+ items: { type: "string" },
1926
+ description: "Nodes produced by checkpoint_iteration"
1927
+ },
1928
+ confidence: {
1929
+ type: "number",
1930
+ minimum: 0,
1931
+ maximum: 1
1932
+ },
1933
+ salience: {
1934
+ type: "number",
1935
+ minimum: 0,
1936
+ maximum: 1
1937
+ },
307
1938
  props: {
308
1939
  type: "object",
309
1940
  description: "Additional properties (e.g. likelihood, impact, mitigation for risks)"
310
1941
  },
1942
+ code_refs: {
1943
+ type: "array",
1944
+ items: { oneOf: [{ type: "string" }, { type: "object" }] },
1945
+ description: "Typed code targets to anchor and attach to created work or execution"
1946
+ },
1947
+ repo: { type: "string", description: "Configured repository id or root" },
1948
+ repo_space_uid: {
1949
+ type: "string",
1950
+ description: "Writable shared repository/Project Space for new code anchors"
1951
+ },
311
1952
  agent_id: {
312
1953
  type: "string",
313
1954
  description: "Agent identity"
314
1955
  }
315
1956
  },
316
1957
  required: ["action"]
1958
+ },
1959
+ annotations: {
1960
+ readOnlyHint: false,
1961
+ destructiveHint: false,
1962
+ idempotentHint: false,
1963
+ openWorldHint: true
317
1964
  }
318
1965
  },
319
1966
  {
@@ -688,14 +2335,45 @@ var TOOLS = [
688
2335
  },
689
2336
  required: ["action"]
690
2337
  }
691
- }
2338
+ },
2339
+ SYNC_TOOL,
2340
+ CODE_TOOL
692
2341
  ];
693
- function ok(data) {
2342
+ var INVOCATION_CONTEXT_SCHEMA = {
2343
+ type: "object",
2344
+ description: "Adapter-owned invocation context. Models should omit it; compatible hooks replace forged or absent values. cwd is consumed locally and never sent to the API.",
2345
+ properties: {
2346
+ harness: { type: "string", enum: ["claude-code", "codex", "generic"] },
2347
+ harnessSessionId: { type: "string" },
2348
+ harnessTurnId: { type: "string" },
2349
+ cwd: { type: "string" },
2350
+ repoId: { type: "string" },
2351
+ branch: { type: "string" },
2352
+ commit: { type: "string" },
2353
+ worktreeState: { type: "string", enum: ["clean", "dirty"] },
2354
+ model: { type: "string" },
2355
+ injectedBy: { type: "string", enum: ["hook", "mcp-process", "caller"] }
2356
+ }
2357
+ };
2358
+ for (const tool of TOOLS) {
2359
+ if (tool.name === "mindgraph_retrieve") continue;
2360
+ const schema = tool.inputSchema;
2361
+ if (schema.properties && !schema.properties.invocation_context) {
2362
+ schema.properties.invocation_context = INVOCATION_CONTEXT_SCHEMA;
2363
+ }
2364
+ }
2365
+ function toolsForProfile(profile = process.env.MINDGRAPH_PROFILE || "general") {
2366
+ if (profile === "coding") return TOOLS;
2367
+ return TOOLS.filter(
2368
+ (tool) => tool.name !== "mindgraph_code" && tool.name !== "mindgraph_sync"
2369
+ );
2370
+ }
2371
+ function ok3(data) {
694
2372
  return {
695
2373
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
696
2374
  };
697
2375
  }
698
- function err(message) {
2376
+ function err3(message) {
699
2377
  return {
700
2378
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
701
2379
  isError: true
@@ -703,29 +2381,53 @@ function err(message) {
703
2381
  }
704
2382
  async function handleTool(client2, name, args) {
705
2383
  try {
2384
+ let result;
706
2385
  switch (name) {
707
2386
  case "mindgraph_capture":
708
- return await handleCapture(client2, args);
2387
+ result = await handleCapture(client2, args);
2388
+ break;
709
2389
  case "mindgraph_reason":
710
- return await handleReason(client2, args);
2390
+ result = await handleReason(client2, args);
2391
+ break;
711
2392
  case "mindgraph_commit":
712
- return await handleCommit(client2, args);
2393
+ result = await handleCommit(client2, args);
2394
+ break;
713
2395
  case "mindgraph_plan":
714
- return await handlePlan(client2, args);
2396
+ result = await handlePlan(client2, args);
2397
+ break;
715
2398
  case "mindgraph_retrieve":
716
- return await handleRetrieve(client2, args);
2399
+ result = await handleRetrieve(client2, args);
2400
+ break;
717
2401
  case "mindgraph_ingest":
718
- return await handleIngest(client2, args);
2402
+ result = await handleIngest(client2, args);
2403
+ break;
719
2404
  case "mindgraph_synthesize":
720
- return await handleSynthesize(client2, args);
2405
+ result = await handleSynthesize(client2, args);
2406
+ break;
721
2407
  case "mindgraph_ontology":
722
- return await handleOntology(client2, args);
2408
+ result = await handleOntology(client2, args);
2409
+ break;
2410
+ case "mindgraph_code":
2411
+ result = await handleCodeTool(client2, args);
2412
+ break;
2413
+ case "mindgraph_sync":
2414
+ result = await handleSyncTool(client2, args);
2415
+ break;
723
2416
  default:
724
- return err(`Unknown tool: ${name}`);
2417
+ result = err3(`Unknown tool: ${name}`);
725
2418
  }
2419
+ const action = typeof args.action === "string" ? args.action : "";
2420
+ const attach = name === "mindgraph_capture" || name === "mindgraph_commit" && action !== "get_open_decisions" || name === "mindgraph_plan" && ![
2421
+ "get_plan",
2422
+ "get_executions",
2423
+ "get_pending",
2424
+ "get_assessments",
2425
+ "resume_work",
2426
+ "heartbeat"
2427
+ ].includes(action);
2428
+ return attach ? await attachCodeRefsToToolResult(client2, result, args) : result;
726
2429
  } catch (e) {
727
- const message = e instanceof Error ? e.message : String(e);
728
- return err(message);
2430
+ return err3(errorDetail(e));
729
2431
  }
730
2432
  }
731
2433
  async function handleCapture(client2, args) {
@@ -734,6 +2436,12 @@ async function handleCapture(client2, args) {
734
2436
  label,
735
2437
  summary,
736
2438
  content,
2439
+ session_uid,
2440
+ work_uid,
2441
+ execution_uid,
2442
+ idempotency_key,
2443
+ supersedes_uid,
2444
+ summarizes_uids,
737
2445
  entity_type,
738
2446
  source_uid,
739
2447
  mood,
@@ -744,12 +2452,30 @@ async function handleCapture(client2, args) {
744
2452
  agent_id
745
2453
  } = args;
746
2454
  switch (action) {
2455
+ case "lesson":
2456
+ return ok3(
2457
+ await client2.distill({
2458
+ label,
2459
+ output_type: "lesson",
2460
+ summary,
2461
+ confidence,
2462
+ salience,
2463
+ session_uid,
2464
+ work_uid,
2465
+ execution_uid,
2466
+ idempotency_key,
2467
+ supersedes_uid,
2468
+ summarizes_uids,
2469
+ props,
2470
+ agent_id
2471
+ })
2472
+ );
747
2473
  case "journal": {
748
- if (!content) return err("content is required for action=journal");
2474
+ if (!content) return err3("content is required for action=journal");
749
2475
  const journalProps = { content };
750
2476
  if (mood) journalProps.mood = mood;
751
2477
  if (tags) journalProps.tags = tags;
752
- return ok(await client2.journal(label, journalProps, { agent_id }));
2478
+ return ok3(await client2.journal(label, journalProps, { agent_id }));
753
2479
  }
754
2480
  case "entity": {
755
2481
  const type = entity_type || "concept";
@@ -757,22 +2483,22 @@ async function handleCapture(client2, args) {
757
2483
  if (summary) entityProps.description = summary;
758
2484
  switch (type) {
759
2485
  case "person":
760
- return ok(await client2.findOrCreatePerson(label, entityProps, agent_id));
2486
+ return ok3(await client2.findOrCreatePerson(label, entityProps, agent_id));
761
2487
  case "organization":
762
- return ok(await client2.findOrCreateOrganization(label, entityProps, agent_id));
2488
+ return ok3(await client2.findOrCreateOrganization(label, entityProps, agent_id));
763
2489
  case "nation":
764
- return ok(await client2.findOrCreateNation(label, entityProps, agent_id));
2490
+ return ok3(await client2.findOrCreateNation(label, entityProps, agent_id));
765
2491
  case "event":
766
- return ok(await client2.findOrCreateEvent(label, entityProps, agent_id));
2492
+ return ok3(await client2.findOrCreateEvent(label, entityProps, agent_id));
767
2493
  case "place":
768
- return ok(await client2.findOrCreatePlace(label, entityProps, agent_id));
2494
+ return ok3(await client2.findOrCreatePlace(label, entityProps, agent_id));
769
2495
  case "concept":
770
2496
  default:
771
- return ok(await client2.findOrCreateConcept(label, entityProps, agent_id));
2497
+ return ok3(await client2.findOrCreateConcept(label, entityProps, agent_id));
772
2498
  }
773
2499
  }
774
2500
  case "observation":
775
- return ok(
2501
+ return ok3(
776
2502
  await client2.capture({
777
2503
  action: "observation",
778
2504
  label,
@@ -784,7 +2510,7 @@ async function handleCapture(client2, args) {
784
2510
  })
785
2511
  );
786
2512
  case "source":
787
- return ok(
2513
+ return ok3(
788
2514
  await client2.capture({
789
2515
  action: "source",
790
2516
  label,
@@ -796,7 +2522,7 @@ async function handleCapture(client2, args) {
796
2522
  })
797
2523
  );
798
2524
  case "snippet":
799
- return ok(
2525
+ return ok3(
800
2526
  await client2.capture({
801
2527
  action: "snippet",
802
2528
  label,
@@ -809,7 +2535,7 @@ async function handleCapture(client2, args) {
809
2535
  })
810
2536
  );
811
2537
  case "concept":
812
- return ok(
2538
+ return ok3(
813
2539
  await client2.structure({
814
2540
  action: "concept",
815
2541
  label,
@@ -821,7 +2547,7 @@ async function handleCapture(client2, args) {
821
2547
  })
822
2548
  );
823
2549
  default:
824
- return err(`Unknown capture action: ${action}`);
2550
+ return err3(`Unknown capture action: ${action}`);
825
2551
  }
826
2552
  }
827
2553
  async function handleReason(client2, args) {
@@ -839,20 +2565,30 @@ async function handleReason(client2, args) {
839
2565
  agent_id
840
2566
  } = args;
841
2567
  if (action === "claim") {
842
- const claimObj = claim || (label ? { label, confidence } : null);
843
- if (!claimObj) return err("claim object or label is required for action=claim");
844
- return ok(
2568
+ const claimObj = claim ? {
2569
+ label: claim.label,
2570
+ confidence: claim.confidence,
2571
+ ...claim.content ? { props: { content: claim.content } } : {}
2572
+ } : label ? { label, confidence } : null;
2573
+ if (!claimObj) return err3("claim object or label is required for action=claim");
2574
+ return ok3(
845
2575
  await client2.argue({
846
2576
  claim: claimObj,
847
- evidence,
848
- warrant,
2577
+ evidence: evidence?.map((e) => ({
2578
+ label: e.label,
2579
+ ...e.description ? { props: { description: e.description } } : {}
2580
+ })),
2581
+ warrant: warrant ? {
2582
+ label: warrant.label,
2583
+ ...warrant.content ? { props: { content: warrant.content } } : {}
2584
+ } : void 0,
849
2585
  argument,
850
2586
  agent_id
851
2587
  })
852
2588
  );
853
2589
  }
854
- if (!label) return err(`label is required for action=${action}`);
855
- return ok(
2590
+ if (!label) return err3(`label is required for action=${action}`);
2591
+ return ok3(
856
2592
  await client2.inquire({
857
2593
  action,
858
2594
  label,
@@ -885,8 +2621,8 @@ async function handleCommit(client2, args) {
885
2621
  case "goal":
886
2622
  case "project":
887
2623
  case "milestone":
888
- if (!label) return err(`label is required for action=${action}`);
889
- return ok(
2624
+ if (!label) return err3(`label is required for action=${action}`);
2625
+ return ok3(
890
2626
  await client2.commit({
891
2627
  action,
892
2628
  label,
@@ -899,15 +2635,15 @@ async function handleCommit(client2, args) {
899
2635
  })
900
2636
  );
901
2637
  case "open_decision":
902
- if (!label) return err("label is required for open_decision");
903
- return ok(await client2.openDecision(label, { summary, props, agent_id }));
2638
+ if (!label) return err3("label is required for open_decision");
2639
+ return ok3(await client2.openDecision(label, { summary, props, agent_id }));
904
2640
  case "add_option":
905
- if (!decision_uid) return err("decision_uid is required for add_option");
906
- if (!label) return err("label is required for add_option");
907
- return ok(await client2.addOption(decision_uid, label, { summary, props, agent_id }));
2641
+ if (!decision_uid) return err3("decision_uid is required for add_option");
2642
+ if (!label) return err3("label is required for add_option");
2643
+ return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id }));
908
2644
  case "add_constraint":
909
- if (!decision_uid) return err("decision_uid is required for add_constraint");
910
- return ok(
2645
+ if (!decision_uid) return err3("decision_uid is required for add_constraint");
2646
+ return ok3(
911
2647
  await client2.deliberate({
912
2648
  action: "add_constraint",
913
2649
  label,
@@ -918,9 +2654,9 @@ async function handleCommit(client2, args) {
918
2654
  })
919
2655
  );
920
2656
  case "resolve_decision":
921
- if (!decision_uid) return err("decision_uid is required for resolve_decision");
922
- if (!chosen_option_uid) return err("chosen_option_uid is required for resolve_decision");
923
- return ok(
2657
+ if (!decision_uid) return err3("decision_uid is required for resolve_decision");
2658
+ if (!chosen_option_uid) return err3("chosen_option_uid is required for resolve_decision");
2659
+ return ok3(
924
2660
  await client2.resolveDecision(decision_uid, chosen_option_uid, {
925
2661
  summary,
926
2662
  props,
@@ -932,9 +2668,9 @@ async function handleCommit(client2, args) {
932
2668
  })
933
2669
  );
934
2670
  case "get_open_decisions":
935
- return ok(await client2.getOpenDecisions());
2671
+ return ok3(await client2.getOpenDecisions());
936
2672
  default:
937
- return err(`Unknown commit action: ${action}`);
2673
+ return err3(`Unknown commit action: ${action}`);
938
2674
  }
939
2675
  }
940
2676
  async function handlePlan(client2, args) {
@@ -944,8 +2680,41 @@ async function handlePlan(client2, args) {
944
2680
  summary,
945
2681
  plan_uid,
946
2682
  task_uid,
2683
+ step_uid,
2684
+ session_uid,
2685
+ goal_uid,
947
2686
  target_uid,
2687
+ execution_uid,
2688
+ executor_uid,
2689
+ affordance_uid,
2690
+ produces_node_uid,
2691
+ filter_plan_uid,
2692
+ depends_on_uids,
2693
+ related_uids,
948
2694
  status,
2695
+ task_status,
2696
+ step_status,
2697
+ execution_status,
2698
+ expected_version,
2699
+ lease_epoch,
2700
+ lease_ttl_secs,
2701
+ idempotency_key,
2702
+ allow_takeover,
2703
+ release_lease,
2704
+ override_reason,
2705
+ scope_uids,
2706
+ limit,
2707
+ confidence,
2708
+ salience,
2709
+ input_snapshot,
2710
+ output_snapshot,
2711
+ side_effects,
2712
+ outcome,
2713
+ error,
2714
+ next_action,
2715
+ checkpoint_summary,
2716
+ test_summary,
2717
+ produces_node_uids,
949
2718
  props,
950
2719
  agent_id
951
2720
  } = args;
@@ -956,25 +2725,120 @@ async function handlePlan(client2, args) {
956
2725
  case "add_step":
957
2726
  case "update_status":
958
2727
  case "get_plan":
959
- return ok(
2728
+ case "resume_work":
2729
+ case "claim_task":
2730
+ case "heartbeat":
2731
+ case "start_iteration":
2732
+ case "checkpoint_iteration":
2733
+ case "block_task":
2734
+ case "complete_task":
2735
+ case "abandon_iteration":
2736
+ return ok3(
960
2737
  await client2.plan({
961
2738
  action,
962
2739
  label,
963
2740
  summary,
2741
+ confidence,
2742
+ salience,
2743
+ goal_uid,
964
2744
  plan_uid,
965
2745
  task_uid,
2746
+ step_uid,
2747
+ session_uid,
2748
+ target_uid,
2749
+ depends_on_uids,
2750
+ related_uids,
966
2751
  status,
2752
+ task_status,
2753
+ step_status,
2754
+ execution_status,
2755
+ execution_uid,
2756
+ expected_version,
2757
+ lease_epoch,
2758
+ lease_ttl_secs,
2759
+ idempotency_key,
2760
+ allow_takeover,
2761
+ release_lease,
2762
+ override_reason,
2763
+ scope_uids,
2764
+ limit,
2765
+ input_snapshot,
2766
+ output_snapshot,
2767
+ side_effects,
2768
+ outcome,
2769
+ error,
2770
+ next_action,
2771
+ checkpoint_summary,
2772
+ test_summary,
2773
+ produces_node_uids,
967
2774
  props,
968
2775
  agent_id
969
2776
  })
970
2777
  );
971
2778
  // Execution tracking
972
2779
  case "start_execution":
973
- return ok(await client2.execution({ action: "start", task_uid, agent_id }));
2780
+ return ok3(
2781
+ await client2.execution({
2782
+ action: "start",
2783
+ label,
2784
+ summary,
2785
+ confidence,
2786
+ salience,
2787
+ plan_uid,
2788
+ executor_uid,
2789
+ affordance_uid,
2790
+ related_uids,
2791
+ input_snapshot,
2792
+ props,
2793
+ agent_id
2794
+ })
2795
+ );
974
2796
  case "complete_execution":
975
- return ok(await client2.execution({ action: "complete", task_uid, agent_id }));
2797
+ return ok3(
2798
+ await client2.execution({
2799
+ action: "complete",
2800
+ execution_uid,
2801
+ produces_node_uid,
2802
+ output_snapshot,
2803
+ side_effects,
2804
+ outcome,
2805
+ props,
2806
+ agent_id
2807
+ })
2808
+ );
976
2809
  case "fail_execution":
977
- return ok(await client2.execution({ action: "fail", task_uid, agent_id }));
2810
+ return ok3(
2811
+ await client2.execution({
2812
+ action: "fail",
2813
+ execution_uid,
2814
+ output_snapshot,
2815
+ side_effects,
2816
+ outcome,
2817
+ error,
2818
+ props,
2819
+ agent_id
2820
+ })
2821
+ );
2822
+ case "register_agent":
2823
+ return ok3(
2824
+ await client2.execution({
2825
+ action: "register_agent",
2826
+ label,
2827
+ summary,
2828
+ confidence,
2829
+ salience,
2830
+ props,
2831
+ agent_id
2832
+ })
2833
+ );
2834
+ case "get_executions":
2835
+ return ok3(
2836
+ await client2.execution({
2837
+ action: "get_executions",
2838
+ filter_plan_uid,
2839
+ agent_id
2840
+ })
2841
+ );
978
2842
  // Governance — read-only from MCP by design (C33). The write actions were
979
2843
  // removed rather than repaired: `resolve_approval` here also sent
980
2844
  // `task_uid` where the server requires `approval_uid`, and never sent
@@ -982,12 +2846,12 @@ async function handlePlan(client2, args) {
982
2846
  // DENIED every approval an agent tried to resolve. Wiring that correctly
983
2847
  // would have meant building a working self-approval path — the hole itself.
984
2848
  case "get_pending":
985
- return ok(await client2.governance({ action: "get_pending", agent_id }));
2849
+ return ok3(await client2.governance({ action: "get_pending", agent_id }));
986
2850
  // Procedures (merged from mindgraph_action)
987
2851
  case "create_flow":
988
2852
  case "add_affordance":
989
2853
  case "add_control":
990
- return ok(
2854
+ return ok3(
991
2855
  await client2.procedure({
992
2856
  action,
993
2857
  label,
@@ -998,7 +2862,7 @@ async function handlePlan(client2, args) {
998
2862
  })
999
2863
  );
1000
2864
  case "add_procedure_step":
1001
- return ok(
2865
+ return ok3(
1002
2866
  await client2.procedure({
1003
2867
  action: "add_step",
1004
2868
  label,
@@ -1010,7 +2874,7 @@ async function handlePlan(client2, args) {
1010
2874
  );
1011
2875
  // Risk assessment (merged from mindgraph_action)
1012
2876
  case "assess_risk":
1013
- return ok(
2877
+ return ok3(
1014
2878
  await client2.risk({
1015
2879
  action: "assess",
1016
2880
  label,
@@ -1021,7 +2885,7 @@ async function handlePlan(client2, args) {
1021
2885
  })
1022
2886
  );
1023
2887
  case "get_assessments":
1024
- return ok(
2888
+ return ok3(
1025
2889
  await client2.risk({
1026
2890
  action: "get_assessments",
1027
2891
  target_uid,
@@ -1029,7 +2893,7 @@ async function handlePlan(client2, args) {
1029
2893
  })
1030
2894
  );
1031
2895
  default:
1032
- return err(`Unknown plan action: ${action}`);
2896
+ return err3(`Unknown plan action: ${action}`);
1033
2897
  }
1034
2898
  }
1035
2899
  async function handleRetrieve(client2, args) {
@@ -1058,8 +2922,8 @@ async function handleRetrieve(client2, args) {
1058
2922
  } = args;
1059
2923
  switch (action) {
1060
2924
  case "context":
1061
- if (!query) return err("query is required for context retrieval");
1062
- return ok(
2925
+ if (!query) return err3("query is required for context retrieval");
2926
+ return ok3(
1063
2927
  await client2.retrieveContext({
1064
2928
  query,
1065
2929
  node_limit: limit,
@@ -1072,8 +2936,8 @@ async function handleRetrieve(client2, args) {
1072
2936
  })
1073
2937
  );
1074
2938
  case "text":
1075
- if (!query) return err("query is required for text search");
1076
- return ok(
2939
+ if (!query) return err3("query is required for text search");
2940
+ return ok3(
1077
2941
  await client2.retrieve({
1078
2942
  action: "text",
1079
2943
  query,
@@ -1084,8 +2948,8 @@ async function handleRetrieve(client2, args) {
1084
2948
  })
1085
2949
  );
1086
2950
  case "semantic":
1087
- if (!query) return err("query is required for semantic search");
1088
- return ok(
2951
+ if (!query) return err3("query is required for semantic search");
2952
+ return ok3(
1089
2953
  await client2.retrieve({
1090
2954
  action: "semantic",
1091
2955
  query,
@@ -1096,8 +2960,8 @@ async function handleRetrieve(client2, args) {
1096
2960
  })
1097
2961
  );
1098
2962
  case "hybrid":
1099
- if (!query) return err("query is required for hybrid search");
1100
- return ok(
2963
+ if (!query) return err3("query is required for hybrid search");
2964
+ return ok3(
1101
2965
  await client2.retrieve({
1102
2966
  action: "hybrid",
1103
2967
  query,
@@ -1109,17 +2973,17 @@ async function handleRetrieve(client2, args) {
1109
2973
  );
1110
2974
  // Structured queries
1111
2975
  case "active_goals":
1112
- return ok(await client2.getGoals());
2976
+ return ok3(await client2.getGoals());
1113
2977
  case "open_questions":
1114
- return ok(await client2.getOpenQuestions());
2978
+ return ok3(await client2.getOpenQuestions());
1115
2979
  case "weak_claims":
1116
- return ok(await client2.getWeakClaims());
2980
+ return ok3(await client2.getWeakClaims());
1117
2981
  case "pending_approvals":
1118
- return ok(await client2.getPendingApprovals());
2982
+ return ok3(await client2.getPendingApprovals());
1119
2983
  case "unresolved_contradictions":
1120
- return ok(await client2.getContradictions());
2984
+ return ok3(await client2.getContradictions());
1121
2985
  case "stale_derivations":
1122
- return ok(
2986
+ return ok3(
1123
2987
  await client2.retrieve({
1124
2988
  action: "stale_derivations",
1125
2989
  limit,
@@ -1127,7 +2991,7 @@ async function handleRetrieve(client2, args) {
1127
2991
  })
1128
2992
  );
1129
2993
  case "preferences":
1130
- return ok(
2994
+ return ok3(
1131
2995
  await client2.retrieve({
1132
2996
  action: "preferences",
1133
2997
  ...query ? { query, k: limit } : {},
@@ -1136,8 +3000,8 @@ async function handleRetrieve(client2, args) {
1136
3000
  })
1137
3001
  );
1138
3002
  case "layer":
1139
- if (!layer) return err("layer is required for layer retrieval");
1140
- return ok(
3003
+ if (!layer) return err3("layer is required for layer retrieval");
3004
+ return ok3(
1141
3005
  await client2.retrieve({
1142
3006
  action: "layer",
1143
3007
  layer,
@@ -1146,7 +3010,7 @@ async function handleRetrieve(client2, args) {
1146
3010
  })
1147
3011
  );
1148
3012
  case "recent":
1149
- return ok(
3013
+ return ok3(
1150
3014
  await client2.retrieve({
1151
3015
  action: "recent",
1152
3016
  limit,
@@ -1158,7 +3022,7 @@ async function handleRetrieve(client2, args) {
1158
3022
  );
1159
3023
  // Document inventory
1160
3024
  case "document_index":
1161
- return ok(
3025
+ return ok3(
1162
3026
  await client2.getNodes({
1163
3027
  node_type: "Document",
1164
3028
  limit: limit ?? 100
@@ -1166,8 +3030,8 @@ async function handleRetrieve(client2, args) {
1166
3030
  );
1167
3031
  // Graph traversal
1168
3032
  case "chain":
1169
- if (!start_uid) return err("start_uid is required for chain traversal");
1170
- return ok(
3033
+ if (!start_uid) return err3("start_uid is required for chain traversal");
3034
+ return ok3(
1171
3035
  await client2.traverse({
1172
3036
  action: "chain",
1173
3037
  start_uid,
@@ -1178,8 +3042,8 @@ async function handleRetrieve(client2, args) {
1178
3042
  })
1179
3043
  );
1180
3044
  case "neighborhood":
1181
- if (!start_uid) return err("start_uid is required for neighborhood traversal");
1182
- return ok(
3045
+ if (!start_uid) return err3("start_uid is required for neighborhood traversal");
3046
+ return ok3(
1183
3047
  await client2.traverse({
1184
3048
  action: "neighborhood",
1185
3049
  start_uid,
@@ -1192,9 +3056,9 @@ async function handleRetrieve(client2, args) {
1192
3056
  })
1193
3057
  );
1194
3058
  case "path":
1195
- if (!start_uid) return err("start_uid is required for path traversal");
1196
- if (!end_uid) return err("end_uid is required for path traversal");
1197
- return ok(
3059
+ if (!start_uid) return err3("start_uid is required for path traversal");
3060
+ if (!end_uid) return err3("end_uid is required for path traversal");
3061
+ return ok3(
1198
3062
  await client2.traverse({
1199
3063
  action: "path",
1200
3064
  start_uid,
@@ -1208,8 +3072,8 @@ async function handleRetrieve(client2, args) {
1208
3072
  })
1209
3073
  );
1210
3074
  case "subgraph":
1211
- if (!start_uid) return err("start_uid is required for subgraph traversal");
1212
- return ok(
3075
+ if (!start_uid) return err3("start_uid is required for subgraph traversal");
3076
+ return ok3(
1213
3077
  await client2.traverse({
1214
3078
  action: "subgraph",
1215
3079
  start_uid,
@@ -1222,7 +3086,7 @@ async function handleRetrieve(client2, args) {
1222
3086
  })
1223
3087
  );
1224
3088
  default:
1225
- return err(`Unknown retrieve action: ${action}`);
3089
+ return err3(`Unknown retrieve action: ${action}`);
1226
3090
  }
1227
3091
  }
1228
3092
  async function handleIngest(client2, args) {
@@ -1251,7 +3115,7 @@ async function handleIngest(client2, args) {
1251
3115
  const targetsOntology = Array.isArray(layers) && layers.includes("ontology");
1252
3116
  const cognitiveLayers = targetsOntology ? layers.filter((layer) => layer !== "ontology") : layers;
1253
3117
  if (targetsOntology && !ontology_schema_id) {
1254
- return err(
3118
+ return err3(
1255
3119
  "layers included 'ontology' but no ontology_schema_id was supplied. Typed Layer-7 extraction is driven by ontology_schema_id, not by the layers list \u2014 pass the schema id, or drop 'ontology' from layers."
1256
3120
  );
1257
3121
  }
@@ -1259,8 +3123,8 @@ async function handleIngest(client2, args) {
1259
3123
  const ontologyOnly = targetsOntology && forwardedLayers === void 0;
1260
3124
  switch (action) {
1261
3125
  case "chunk":
1262
- if (!content) return err("content is required for chunk ingestion");
1263
- return ok(
3126
+ if (!content) return err3("content is required for chunk ingestion");
3127
+ return ok3(
1264
3128
  await client2.ingestChunk({
1265
3129
  content,
1266
3130
  label: title,
@@ -1274,8 +3138,8 @@ async function handleIngest(client2, args) {
1274
3138
  })
1275
3139
  );
1276
3140
  case "document":
1277
- if (!content) return err("content is required for document ingestion");
1278
- return ok(
3141
+ if (!content) return err3("content is required for document ingestion");
3142
+ return ok3(
1279
3143
  await client2.ingestDocument({
1280
3144
  content,
1281
3145
  title,
@@ -1294,8 +3158,8 @@ async function handleIngest(client2, args) {
1294
3158
  })
1295
3159
  );
1296
3160
  case "session":
1297
- if (!content) return err("content is required for session ingestion");
1298
- return ok(
3161
+ if (!content) return err3("content is required for session ingestion");
3162
+ return ok3(
1299
3163
  await client2.ingestSession({
1300
3164
  content,
1301
3165
  title,
@@ -1312,11 +3176,11 @@ async function handleIngest(client2, args) {
1312
3176
  );
1313
3177
  case "job_status":
1314
3178
  if (job_id) {
1315
- return ok(await client2.getJob(job_id));
3179
+ return ok3(await client2.getJob(job_id));
1316
3180
  }
1317
- return ok(await client2.listJobs());
3181
+ return ok3(await client2.listJobs());
1318
3182
  default:
1319
- return err(`Unknown ingest action: ${action}`);
3183
+ return err3(`Unknown ingest action: ${action}`);
1320
3184
  }
1321
3185
  }
1322
3186
  async function handleSynthesize(client2, args) {
@@ -1324,19 +3188,19 @@ async function handleSynthesize(client2, args) {
1324
3188
  switch (action) {
1325
3189
  case "signals":
1326
3190
  if (!project_uid)
1327
- return err("project_uid is required for action='signals'");
1328
- return ok(
3191
+ return err3("project_uid is required for action='signals'");
3192
+ return ok3(
1329
3193
  await client2.signals(project_uid, { signals, target_types })
1330
3194
  );
1331
3195
  case "run":
1332
3196
  if (!project_uid)
1333
- return err("project_uid is required for action='run'");
1334
- return ok(await client2.runSynthesis(project_uid));
3197
+ return err3("project_uid is required for action='run'");
3198
+ return ok3(await client2.runSynthesis(project_uid));
1335
3199
  case "job_status":
1336
- if (!job_id) return err("job_id is required for action='job_status'");
1337
- return ok(await client2.getJob(job_id));
3200
+ if (!job_id) return err3("job_id is required for action='job_status'");
3201
+ return ok3(await client2.getJob(job_id));
1338
3202
  default:
1339
- return err(`Unknown synthesize action: ${action}`);
3203
+ return err3(`Unknown synthesize action: ${action}`);
1340
3204
  }
1341
3205
  }
1342
3206
  async function handleOntology(client2, args) {
@@ -1364,18 +3228,18 @@ async function handleOntology(client2, args) {
1364
3228
  } = args;
1365
3229
  switch (action) {
1366
3230
  case "schemas":
1367
- return ok(await client2.listOntologySchemas());
3231
+ return ok3(await client2.listOntologySchemas());
1368
3232
  case "schema":
1369
- if (!schema_id) return err("schema_id is required for action='schema'");
1370
- return ok(await client2.getOntologySchema(schema_id));
3233
+ if (!schema_id) return err3("schema_id is required for action='schema'");
3234
+ return ok3(await client2.getOntologySchema(schema_id));
1371
3235
  case "query": {
1372
- if (!query) return err("query is required for action='query'");
3236
+ if (!query) return err3("query is required for action='query'");
1373
3237
  if (!schema_id) {
1374
- return err(
3238
+ return err3(
1375
3239
  "schema_id is required for action='query' (use action='schemas' to find the active schema)"
1376
3240
  );
1377
3241
  }
1378
- return ok(
3242
+ return ok3(
1379
3243
  await client2.queryOntology({
1380
3244
  query,
1381
3245
  schema_id,
@@ -1388,8 +3252,8 @@ async function handleOntology(client2, args) {
1388
3252
  );
1389
3253
  }
1390
3254
  case "search":
1391
- if (!query) return err("query is required for action='search'");
1392
- return ok(
3255
+ if (!query) return err3("query is required for action='search'");
3256
+ return ok3(
1393
3257
  await client2.searchDomainObjects(query, {
1394
3258
  schema_id,
1395
3259
  object_types,
@@ -1397,18 +3261,18 @@ async function handleOntology(client2, args) {
1397
3261
  })
1398
3262
  );
1399
3263
  case "objects":
1400
- if (!schema_id) return err("schema_id is required for action='objects'");
1401
- return ok(
3264
+ if (!schema_id) return err3("schema_id is required for action='objects'");
3265
+ return ok3(
1402
3266
  await client2.listDomainObjects({ schema_id, object_type, limit })
1403
3267
  );
1404
3268
  case "object":
1405
- if (!uid) return err("uid is required for action='object'");
1406
- return ok(await client2.getDomainObject(uid));
3269
+ if (!uid) return err3("uid is required for action='object'");
3270
+ return ok3(await client2.getDomainObject(uid));
1407
3271
  case "object_context":
1408
- if (!uid) return err("uid is required for action='object_context'");
1409
- return ok(await client2.getDomainObjectContext(uid, depth));
3272
+ if (!uid) return err3("uid is required for action='object_context'");
3273
+ return ok3(await client2.getDomainObjectContext(uid, depth));
1410
3274
  case "proposals":
1411
- return ok(
3275
+ return ok3(
1412
3276
  await client2.listOntologyProposals({
1413
3277
  status: status ?? "pending",
1414
3278
  schema_id,
@@ -1417,21 +3281,21 @@ async function handleOntology(client2, args) {
1417
3281
  })
1418
3282
  );
1419
3283
  case "proposal":
1420
- if (!proposal_id) return err("proposal_id is required for action='proposal'");
1421
- return ok(await client2.getOntologyProposal(proposal_id));
3284
+ if (!proposal_id) return err3("proposal_id is required for action='proposal'");
3285
+ return ok3(await client2.getOntologyProposal(proposal_id));
1422
3286
  case "approve":
1423
- if (!proposal_id) return err("proposal_id is required for action='approve'");
1424
- return ok(await client2.approveOntologyProposal(proposal_id, { feedback }));
3287
+ if (!proposal_id) return err3("proposal_id is required for action='approve'");
3288
+ return ok3(await client2.approveOntologyProposal(proposal_id, { feedback }));
1425
3289
  case "reject":
1426
- if (!proposal_id) return err("proposal_id is required for action='reject'");
1427
- return ok(await client2.rejectOntologyProposal(proposal_id, reason));
3290
+ if (!proposal_id) return err3("proposal_id is required for action='reject'");
3291
+ return ok3(await client2.rejectOntologyProposal(proposal_id, reason));
1428
3292
  case "link": {
1429
3293
  if (!from_uid || !to_uid || !relation_type) {
1430
- return err(
3294
+ return err3(
1431
3295
  "from_uid, to_uid, and relation_type are required for action='link'"
1432
3296
  );
1433
3297
  }
1434
- return ok(
3298
+ return ok3(
1435
3299
  await client2.linkDomainObjects({
1436
3300
  from_uid,
1437
3301
  to_uid,
@@ -1442,11 +3306,11 @@ async function handleOntology(client2, args) {
1442
3306
  );
1443
3307
  }
1444
3308
  case "extract": {
1445
- if (!schema_id) return err("schema_id is required for action='extract'");
3309
+ if (!schema_id) return err3("schema_id is required for action='extract'");
1446
3310
  if (!source_uids?.length) {
1447
- return err("source_uids is required for action='extract'");
3311
+ return err3("source_uids is required for action='extract'");
1448
3312
  }
1449
- return ok(
3313
+ return ok3(
1450
3314
  await client2.extractOntology({
1451
3315
  ontology_schema_id: schema_id,
1452
3316
  source_uids
@@ -1454,15 +3318,15 @@ async function handleOntology(client2, args) {
1454
3318
  );
1455
3319
  }
1456
3320
  default:
1457
- return err(`Unknown ontology action: ${action}`);
3321
+ return err3(`Unknown ontology action: ${action}`);
1458
3322
  }
1459
3323
  }
1460
3324
 
1461
3325
  // src/generated-tools.ts
1462
- var ok2 = (data) => ({
3326
+ var ok4 = (data) => ({
1463
3327
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
1464
3328
  });
1465
- var err2 = (message) => ({
3329
+ var err4 = (message) => ({
1466
3330
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
1467
3331
  isError: true
1468
3332
  });
@@ -1529,10 +3393,10 @@ async function handleGeneratedTool(client2, desc, args) {
1529
3393
  switch (desc.maps_to) {
1530
3394
  case "search": {
1531
3395
  const query = args.query;
1532
- if (!query) return err2(`query is required for ${desc.name}`);
3396
+ if (!query) return err4(`query is required for ${desc.name}`);
1533
3397
  const limit = typeof args.limit === "number" ? args.limit : void 0;
1534
3398
  const filters = Array.isArray(args.filters) ? args.filters : void 0;
1535
- return ok2(
3399
+ return ok4(
1536
3400
  await ontologyClient.searchDomainObjects(query, {
1537
3401
  schema_id: desc.schema_id,
1538
3402
  object_types: [desc.object_type],
@@ -1543,33 +3407,33 @@ async function handleGeneratedTool(client2, desc, args) {
1543
3407
  }
1544
3408
  case "object": {
1545
3409
  const uid = args.uid;
1546
- if (!uid) return err2(`uid is required for ${desc.name}`);
1547
- return ok2(await ontologyClient.getDomainObject(uid, {
3410
+ if (!uid) return err4(`uid is required for ${desc.name}`);
3411
+ return ok4(await ontologyClient.getDomainObject(uid, {
1548
3412
  schema_id: desc.schema_id,
1549
3413
  object_type: desc.object_type
1550
3414
  }));
1551
3415
  }
1552
3416
  case "object_context": {
1553
3417
  const uid = args.uid;
1554
- if (!uid) return err2(`uid is required for ${desc.name}`);
3418
+ if (!uid) return err4(`uid is required for ${desc.name}`);
1555
3419
  const depth = typeof args.depth === "number" ? args.depth : void 0;
1556
- return ok2(await ontologyClient.getDomainObjectContext(uid, depth, {
3420
+ return ok4(await ontologyClient.getDomainObjectContext(uid, depth, {
1557
3421
  schema_id: desc.schema_id,
1558
3422
  object_type: desc.object_type
1559
3423
  }));
1560
3424
  }
1561
3425
  case "related": {
1562
3426
  const uid = args.uid;
1563
- if (!uid) return err2(`uid is required for ${desc.name}`);
3427
+ if (!uid) return err4(`uid is required for ${desc.name}`);
1564
3428
  if (!desc.relation || !desc.entry_role || !desc.far_type) {
1565
- return err2(`invalid related descriptor: ${desc.name}`);
3429
+ return err4(`invalid related descriptor: ${desc.name}`);
1566
3430
  }
1567
3431
  if (!ontologyClient.queryRelatedDomainObjects) {
1568
- return err2(
3432
+ return err4(
1569
3433
  "related ontology tools require a graph-aware version of the mindgraph SDK"
1570
3434
  );
1571
3435
  }
1572
- return ok2(await ontologyClient.queryRelatedDomainObjects({
3436
+ return ok4(await ontologyClient.queryRelatedDomainObjects({
1573
3437
  schema_id: desc.schema_id,
1574
3438
  entry_type: desc.object_type,
1575
3439
  uid,
@@ -1584,9 +3448,9 @@ async function handleGeneratedTool(client2, desc, args) {
1584
3448
  }
1585
3449
  case "structured_query": {
1586
3450
  const select = args.select;
1587
- if (!select) return err2(`select is required for ${desc.name}`);
3451
+ if (!select) return err4(`select is required for ${desc.name}`);
1588
3452
  if (!ontologyClient.queryDomainStructured) {
1589
- return err2(
3453
+ return err4(
1590
3454
  "structured ontology tools require a graph-aware version of the mindgraph SDK"
1591
3455
  );
1592
3456
  }
@@ -1597,13 +3461,13 @@ async function handleGeneratedTool(client2, desc, args) {
1597
3461
  for (const field of STRUCTURED_QUERY_PASSTHROUGH) {
1598
3462
  if (args[field] !== void 0) request[field] = args[field];
1599
3463
  }
1600
- return ok2(await ontologyClient.queryDomainStructured(request));
3464
+ return ok4(await ontologyClient.queryDomainStructured(request));
1601
3465
  }
1602
3466
  default:
1603
- return err2(`unknown generated tool mapping: ${desc.maps_to}`);
3467
+ return err4(`unknown generated tool mapping: ${desc.maps_to}`);
1604
3468
  }
1605
3469
  } catch (e) {
1606
- return err2(e instanceof Error ? e.message : String(e));
3470
+ return err4(e instanceof Error ? e.message : String(e));
1607
3471
  }
1608
3472
  }
1609
3473
 
@@ -1617,7 +3481,7 @@ function isTransientStatus(status) {
1617
3481
  return status === 408 || status === 425 || status === 429 || status >= 500;
1618
3482
  }
1619
3483
  function sleep(ms) {
1620
- return new Promise((resolve) => setTimeout(resolve, ms));
3484
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
1621
3485
  }
1622
3486
  var KNOWN_DUTIES = /* @__PURE__ */ new Set(["log", "require_approval"]);
1623
3487
  function headers(apiKey, orgId) {
@@ -1634,6 +3498,105 @@ function unsupportedResponse(status, body) {
1634
3498
  const lower = body.toLowerCase();
1635
3499
  return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
1636
3500
  }
3501
+ var PLAN_READ_ACTIONS = /* @__PURE__ */ new Set([
3502
+ "get_plan",
3503
+ "get_executions",
3504
+ "get_pending",
3505
+ "get_assessments",
3506
+ "resume_work"
3507
+ ]);
3508
+ var ONTOLOGY_READ_ACTIONS = /* @__PURE__ */ new Set([
3509
+ "list_schemas",
3510
+ "get_schema",
3511
+ "query",
3512
+ "search_objects",
3513
+ "list_objects",
3514
+ "get_object",
3515
+ "get_context",
3516
+ "list_proposals",
3517
+ "get_proposal"
3518
+ ]);
3519
+ function toolMutability(toolName, action) {
3520
+ if (toolName === "mindgraph_retrieve") return "read";
3521
+ if (toolName === "mindgraph_plan") {
3522
+ return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
3523
+ }
3524
+ if (toolName === "mindgraph_ingest") {
3525
+ return action === "job_status" ? "read" : "write";
3526
+ }
3527
+ if (toolName === "mindgraph_synthesize") {
3528
+ return action === "signals" ? "read" : "write";
3529
+ }
3530
+ if (toolName === "mindgraph_code") {
3531
+ return action === "anchor" ? "write" : "read";
3532
+ }
3533
+ if (toolName === "mindgraph_sync") {
3534
+ return action === "scan" || action === "status" ? "read" : "write";
3535
+ }
3536
+ if (toolName === "mindgraph_ontology") {
3537
+ return action && ONTOLOGY_READ_ACTIONS.has(action) ? "read" : "write";
3538
+ }
3539
+ if (/_(search|get|context|related|query)$/.test(toolName) && toolName !== "mindgraph_capture") {
3540
+ return "read";
3541
+ }
3542
+ return "write";
3543
+ }
3544
+ var UID_FIELDS = [
3545
+ "uid",
3546
+ "source_uid",
3547
+ "session_uid",
3548
+ "work_uid",
3549
+ "goal_uid",
3550
+ "project_uid",
3551
+ "task_uid",
3552
+ "plan_uid",
3553
+ "step_uid",
3554
+ "target_uid",
3555
+ "execution_uid",
3556
+ "executor_uid",
3557
+ "affordance_uid",
3558
+ "produces_node_uid",
3559
+ "filter_plan_uid",
3560
+ "parent_uid",
3561
+ "decision_uid",
3562
+ "chosen_option_uid",
3563
+ "governed_uid",
3564
+ "approval_uid",
3565
+ "requires_plan_uid",
3566
+ "start_uid",
3567
+ "end_uid"
3568
+ ];
3569
+ var UID_ARRAY_FIELDS = [
3570
+ "related_uids",
3571
+ "depends_on_uids",
3572
+ "summarizes_uids",
3573
+ "informs_uid",
3574
+ "target_uids",
3575
+ "anchor_uids",
3576
+ "scope_uids",
3577
+ "produces_node_uids"
3578
+ ];
3579
+ function governanceTarget(toolName, args) {
3580
+ const action = typeof args.action === "string" ? args.action : void 0;
3581
+ const targetUids = /* @__PURE__ */ new Set();
3582
+ for (const field of UID_FIELDS) {
3583
+ const value = args[field];
3584
+ if (typeof value === "string" && value.length > 0) targetUids.add(value);
3585
+ }
3586
+ for (const field of UID_ARRAY_FIELDS) {
3587
+ const value = args[field];
3588
+ if (!Array.isArray(value)) continue;
3589
+ for (const uid of value) {
3590
+ if (typeof uid === "string" && uid.length > 0) targetUids.add(uid);
3591
+ }
3592
+ }
3593
+ return {
3594
+ tool_name: toolName,
3595
+ ...action ? { action } : {},
3596
+ mutability: toolMutability(toolName, action),
3597
+ target_uids: [...targetUids]
3598
+ };
3599
+ }
1637
3600
  async function checkMcpGovernance(toolName, args, config) {
1638
3601
  if (config.disabled) return { allowed: true };
1639
3602
  if (capability === "unsupported") {
@@ -1656,7 +3619,7 @@ async function checkMcpGovernance(toolName, args, config) {
1656
3619
  action: "check",
1657
3620
  act: "tool_invoke",
1658
3621
  agent_id: String(args.agent_id || config.agentId),
1659
- target: { tool_name: toolName },
3622
+ target: governanceTarget(toolName, args),
1660
3623
  context: { adapter: "mindgraph-mcp", ...config.context },
1661
3624
  tier: "checkpoint"
1662
3625
  })
@@ -1853,13 +3816,15 @@ var API_KEY = process.env.MINDGRAPH_API_KEY;
1853
3816
  var BASE_URL = process.env.MINDGRAPH_BASE_URL || "https://api.mindgraph.cloud";
1854
3817
  var AGENT_ID = process.env.MINDGRAPH_AGENT_ID || "mcp";
1855
3818
  var ORG_ID = process.env.MINDGRAPH_ORG_ID;
3819
+ var PROFILE = process.env.MINDGRAPH_PROFILE || "general";
3820
+ var HARNESS = process.env.MINDGRAPH_HARNESS || "generic";
1856
3821
  if (!API_KEY) {
1857
3822
  console.error(
1858
3823
  "Error: MINDGRAPH_API_KEY environment variable is required.\nGet your API key at https://mindgraph.cloud/dashboard/keys\nOr run: npx mindgraph-mcp init"
1859
3824
  );
1860
3825
  process.exit(1);
1861
3826
  }
1862
- var client = new import_mindgraph.MindGraph({
3827
+ var client = new import_mindgraph2.MindGraph({
1863
3828
  baseUrl: BASE_URL,
1864
3829
  apiKey: API_KEY,
1865
3830
  orgId: ORG_ID,
@@ -1868,7 +3833,7 @@ var client = new import_mindgraph.MindGraph({
1868
3833
  // window where npm may still resolve the preceding SDK declaration file.
1869
3834
  telemetrySurface: "mcp"
1870
3835
  });
1871
- var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph (7 tools).
3836
+ var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph, plus any ontology tools generated by the active schema.
1872
3837
 
1873
3838
  ## #1 RULE: Go straight to the user's topic
1874
3839
 
@@ -1931,22 +3896,42 @@ Capture knowledge when the user shares something worth remembering:
1931
3896
  - Questions to track \u2192 \`mindgraph_reason\` action "open_question"
1932
3897
  - Goals or projects \u2192 \`mindgraph_commit\` action "goal"/"project"
1933
3898
  - Decisions \u2192 \`mindgraph_commit\` action "open_decision"
3899
+ - Durable engineering work that must survive sessions/harnesses \u2192 \`mindgraph_plan\`
3900
+ - Typed code anchors, attached memory/work, callers/callees, or impact \u2192 \`mindgraph_code\`
3901
+ - Reusable learning from a material attempt \u2192 \`mindgraph_capture\` action "lesson"
1934
3902
  - Long-form content \u2192 \`mindgraph_ingest\`
1935
3903
  - Cross-document synthesis over a project corpus \u2192 \`mindgraph_synthesize\` (action "signals" for structural signals; action "run" to spawn a synthesis job that writes Article nodes)
1936
3904
 
1937
3905
  ## Tool tips
1938
3906
 
3907
+ - Use the harness todo list to organize only the current harness's local execution. Use \`mindgraph_plan\` when work is authoritative across sessions/harnesses, needs graph relationships or evidence, or must be visible to other agents. Do not maintain the same item in both.
3908
+ - If a local harness task remains unfinished and should become authoritative outside that local list, promote it once with a stable idempotency key when the graph-managed composite actions are available; otherwise do not copy it.
1939
3909
  - \`capture\`: "entity"/"observation" for facts, "journal" for personal/informal
1940
3910
  - \`reason\`: "claim" when evidence exists, "open_question"/"hypothesis" otherwise
1941
3911
  - \`retrieve\`: "context" returns graph nodes only by default \u2014 set include_chunks=true for source text
1942
3912
  - \`retrieve\`: "context" (FTS default) \u2192 "semantic" (conceptual fallback) \u2192 "hybrid" (both)
1943
3913
  - \`retrieve\`: "neighborhood"/"chain"/"path"/"subgraph" for graph exploration
3914
+ - \`code\`: pass path + symbol + signature when names are overloaded; ambiguity never writes
1944
3915
  - Confidence: 0.9+ for facts, 0.5-0.8 for uncertain, <0.5 for speculation
1945
3916
  - Don't narrate tool usage \u2014 capture naturally as part of conversation`;
3917
+ if (PROFILE === "coding") {
3918
+ INSTRUCTIONS += `
3919
+
3920
+ ## Coding profile
3921
+
3922
+ - Use mindgraph_sync for explicit, one-way project memory-file imports. It discovers and hashes files, but you deliberately map durable assertions with record; it never writes graph state back to files.
3923
+ - Capture corrections, decisions with rationale, fixes that survived meaningful failed attempts, durable invariants/preferences, and blockers with evidence.
3924
+ - Do not capture routine mechanics, transient command output, facts cheaply derivable from code, unsupported speculation as high-confidence lessons, or completion without evidence.
3925
+ - Adapter context is owned by ${HARNESS}; omit invocation_context because hooks replace it.`;
3926
+ } else {
3927
+ INSTRUCTIONS = INSTRUCTIONS.split("\n").filter(
3928
+ (line) => !line.includes("mindgraph_code") && !line.includes("`code`") && !line.includes("Typed code anchors")
3929
+ ).join("\n");
3930
+ }
1946
3931
  var server = new import_server.Server(
1947
3932
  {
1948
3933
  name: "mindgraph",
1949
- version: "0.13.5"
3934
+ version: "0.14.1"
1950
3935
  },
1951
3936
  {
1952
3937
  capabilities: {
@@ -1959,7 +3944,7 @@ var server = new import_server.Server(
1959
3944
  );
1960
3945
  server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
1961
3946
  const generated = await getGeneratedTools(client);
1962
- return { tools: [...TOOLS, ...generated.tools] };
3947
+ return { tools: [...toolsForProfile(PROFILE), ...generated.tools] };
1963
3948
  });
1964
3949
  var GOVERNANCE_CONFIG = {
1965
3950
  baseUrl: BASE_URL,