mindgraph-mcp 0.14.1 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +941 -25
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,895 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
|
|
29
|
+
// node_modules/mindgraph/dist/index.mjs
|
|
30
|
+
function seg(value) {
|
|
31
|
+
return encodeURIComponent(String(value));
|
|
32
|
+
}
|
|
33
|
+
function createRequestId() {
|
|
34
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
35
|
+
return globalThis.crypto.randomUUID();
|
|
36
|
+
}
|
|
37
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
38
|
+
}
|
|
39
|
+
var MindGraphError, MindGraph;
|
|
40
|
+
var init_dist = __esm({
|
|
41
|
+
"node_modules/mindgraph/dist/index.mjs"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
MindGraphError = class extends Error {
|
|
44
|
+
constructor(message, status, body) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.status = status;
|
|
47
|
+
this.body = body;
|
|
48
|
+
this.name = "MindGraphError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
MindGraph = class {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
54
|
+
this.headers = { "Content-Type": "application/json" };
|
|
55
|
+
if (config.apiKey) {
|
|
56
|
+
this.headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
57
|
+
} else if (config.jwt) {
|
|
58
|
+
this.headers["Authorization"] = `Bearer ${config.jwt}`;
|
|
59
|
+
}
|
|
60
|
+
if (config.orgId) {
|
|
61
|
+
this.headers["X-MindGraph-Org"] = config.orgId;
|
|
62
|
+
}
|
|
63
|
+
this.telemetrySurface = config.telemetrySurface;
|
|
64
|
+
this.maxRetries = config.maxRetries ?? 3;
|
|
65
|
+
this.retryBackoffMs = config.retryBackoffMs ?? 1e3;
|
|
66
|
+
}
|
|
67
|
+
// ---- HTTP helpers ----
|
|
68
|
+
async request(method, path6, body) {
|
|
69
|
+
const url = `${this.baseUrl}${path6}`;
|
|
70
|
+
const requestId = createRequestId();
|
|
71
|
+
const init = {
|
|
72
|
+
method,
|
|
73
|
+
headers: {
|
|
74
|
+
...this.headers,
|
|
75
|
+
"X-MindGraph-Request-ID": requestId,
|
|
76
|
+
...this.telemetrySurface ? { "X-MindGraph-Surface": this.telemetrySurface } : {}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
if (body !== void 0) {
|
|
80
|
+
init.body = JSON.stringify(body);
|
|
81
|
+
}
|
|
82
|
+
let lastError;
|
|
83
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
84
|
+
const res = await fetch(url, init);
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
const text2 = await res.text().catch(() => "");
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(text2);
|
|
90
|
+
} catch {
|
|
91
|
+
parsed = text2;
|
|
92
|
+
}
|
|
93
|
+
const err5 = new MindGraphError(
|
|
94
|
+
`${method} ${path6} failed: ${res.status}`,
|
|
95
|
+
res.status,
|
|
96
|
+
parsed
|
|
97
|
+
);
|
|
98
|
+
if (res.status === 503 && attempt < this.maxRetries) {
|
|
99
|
+
lastError = err5;
|
|
100
|
+
const delay = this.retryBackoffMs * 2 ** attempt;
|
|
101
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
throw err5;
|
|
105
|
+
}
|
|
106
|
+
const text = await res.text();
|
|
107
|
+
if (!text) return void 0;
|
|
108
|
+
return JSON.parse(text);
|
|
109
|
+
}
|
|
110
|
+
throw lastError;
|
|
111
|
+
}
|
|
112
|
+
get(path6) {
|
|
113
|
+
return this.request("GET", path6);
|
|
114
|
+
}
|
|
115
|
+
post(path6, body) {
|
|
116
|
+
return this.request("POST", path6, body);
|
|
117
|
+
}
|
|
118
|
+
patch(path6, body) {
|
|
119
|
+
return this.request("PATCH", path6, body);
|
|
120
|
+
}
|
|
121
|
+
del(path6) {
|
|
122
|
+
return this.request("DELETE", path6);
|
|
123
|
+
}
|
|
124
|
+
// ---- Health ----
|
|
125
|
+
async health() {
|
|
126
|
+
return this.get("/health");
|
|
127
|
+
}
|
|
128
|
+
async stats() {
|
|
129
|
+
return this.get("/stats");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Schema fill-rate report (measure-first tiering): per live node type,
|
|
133
|
+
* the exact live count and sampled per-field fill rates; near-empty
|
|
134
|
+
* fields flagged below 5%. `sample` caps per-type sampling (default
|
|
135
|
+
* 1000); `layer` restricts (e.g. "epistemic").
|
|
136
|
+
*/
|
|
137
|
+
async schemaFillStats(params) {
|
|
138
|
+
const q = new URLSearchParams();
|
|
139
|
+
if (params?.sample !== void 0) q.set("sample", String(params.sample));
|
|
140
|
+
if (params?.layer) q.set("layer", params.layer);
|
|
141
|
+
const qs = q.toString();
|
|
142
|
+
return this.get(`/stats/schema-fill${qs ? `?${qs}` : ""}`);
|
|
143
|
+
}
|
|
144
|
+
// ---- Reality Layer ----
|
|
145
|
+
async capture(req) {
|
|
146
|
+
return this.post("/reality/capture", req);
|
|
147
|
+
}
|
|
148
|
+
async entity(req) {
|
|
149
|
+
return this.post("/reality/entity", req);
|
|
150
|
+
}
|
|
151
|
+
/** Convenience: create or find an entity by label. */
|
|
152
|
+
async findOrCreateEntity(label, props, agentId) {
|
|
153
|
+
return this.post("/reality/entity", {
|
|
154
|
+
action: "create",
|
|
155
|
+
label,
|
|
156
|
+
props: { entity_type: "other", ...props },
|
|
157
|
+
agent_id: agentId
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/** Convenience: create or find a Person entity by label. */
|
|
161
|
+
async findOrCreatePerson(label, props, agentId) {
|
|
162
|
+
return this.findOrCreateEntity(label, { entity_type: "person", ...props }, agentId);
|
|
163
|
+
}
|
|
164
|
+
/** Convenience: create or find an Organization entity by label. */
|
|
165
|
+
async findOrCreateOrganization(label, props, agentId) {
|
|
166
|
+
return this.findOrCreateEntity(label, { entity_type: "organization", ...props }, agentId);
|
|
167
|
+
}
|
|
168
|
+
/** Convenience: create or find a Nation entity by label. */
|
|
169
|
+
async findOrCreateNation(label, props, agentId) {
|
|
170
|
+
return this.findOrCreateEntity(label, { entity_type: "nation", ...props }, agentId);
|
|
171
|
+
}
|
|
172
|
+
/** Convenience: create or find an Event entity by label. */
|
|
173
|
+
async findOrCreateEvent(label, props, agentId) {
|
|
174
|
+
return this.findOrCreateEntity(label, { entity_type: "event", ...props }, agentId);
|
|
175
|
+
}
|
|
176
|
+
/** Convenience: create or find a Place entity by label. */
|
|
177
|
+
async findOrCreatePlace(label, props, agentId) {
|
|
178
|
+
return this.findOrCreateEntity(label, { entity_type: "place", ...props }, agentId);
|
|
179
|
+
}
|
|
180
|
+
/** Convenience: create or find a Concept entity by label. */
|
|
181
|
+
async findOrCreateConcept(label, props, agentId) {
|
|
182
|
+
return this.findOrCreateEntity(label, { entity_type: "concept", ...props }, agentId);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve text to an existing entity via alias matching.
|
|
186
|
+
* Returns `{ uid: string | null }`.
|
|
187
|
+
*/
|
|
188
|
+
async resolveEntity(text, agentId) {
|
|
189
|
+
return this.post("/reality/entity", {
|
|
190
|
+
action: "resolve",
|
|
191
|
+
text,
|
|
192
|
+
agent_id: agentId
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Fuzzy-match text against existing entities.
|
|
197
|
+
* Returns `{ matches: [{ uid, label, score }] }`.
|
|
198
|
+
*/
|
|
199
|
+
async fuzzyResolveEntity(text, limit = 5, agentId) {
|
|
200
|
+
return this.post("/reality/entity", {
|
|
201
|
+
action: "fuzzy_resolve",
|
|
202
|
+
text,
|
|
203
|
+
limit,
|
|
204
|
+
agent_id: agentId
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// ---- Epistemic Layer ----
|
|
208
|
+
async argue(req) {
|
|
209
|
+
return this.post("/epistemic/argument", req);
|
|
210
|
+
}
|
|
211
|
+
async inquire(req) {
|
|
212
|
+
return this.post("/epistemic/inquiry", req);
|
|
213
|
+
}
|
|
214
|
+
async structure(req) {
|
|
215
|
+
return this.post("/epistemic/structure", req);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Convenience: create a Claim node via the argument endpoint.
|
|
219
|
+
* Returns the full argument response including `claim_uid`.
|
|
220
|
+
*/
|
|
221
|
+
async addClaim(label, content, confidence, agentId) {
|
|
222
|
+
return this.post("/epistemic/argument", {
|
|
223
|
+
claim: {
|
|
224
|
+
label,
|
|
225
|
+
confidence,
|
|
226
|
+
props: { content }
|
|
227
|
+
},
|
|
228
|
+
agent_id: agentId
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Convenience: create an Evidence node attached to a claim via the argument endpoint.
|
|
233
|
+
* If `claimLabel` and `claimConfidence` are provided, also creates the claim.
|
|
234
|
+
*/
|
|
235
|
+
async addEvidence(label, description, agentId) {
|
|
236
|
+
return this.post("/epistemic/argument", {
|
|
237
|
+
claim: { label: `Claim for: ${label}` },
|
|
238
|
+
evidence: [{ label, props: { description } }],
|
|
239
|
+
agent_id: agentId
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/** Convenience: create an Observation node via the reality capture endpoint. */
|
|
243
|
+
async addObservation(label, description, agentId) {
|
|
244
|
+
return this.post("/reality/capture", {
|
|
245
|
+
action: "observation",
|
|
246
|
+
label,
|
|
247
|
+
summary: description,
|
|
248
|
+
agent_id: agentId
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
// ---- Intent Layer ----
|
|
252
|
+
async commit(req) {
|
|
253
|
+
return this.post("/intent/commitment", req);
|
|
254
|
+
}
|
|
255
|
+
async deliberate(req) {
|
|
256
|
+
return this.post("/intent/deliberation", req);
|
|
257
|
+
}
|
|
258
|
+
/** Open a new decision for deliberation. Returns the Decision node. */
|
|
259
|
+
async openDecision(label, opts) {
|
|
260
|
+
return this.post("/intent/deliberation", {
|
|
261
|
+
action: "open_decision",
|
|
262
|
+
label,
|
|
263
|
+
...opts
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/** Add an option to an open decision. Returns the Option node. */
|
|
267
|
+
async addOption(decisionUid, label, opts) {
|
|
268
|
+
return this.post("/intent/deliberation", {
|
|
269
|
+
action: "add_option",
|
|
270
|
+
decision_uid: decisionUid,
|
|
271
|
+
label,
|
|
272
|
+
...opts
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Resolve a decision by choosing an option.
|
|
277
|
+
* `chosenOptionUid` must be the uid of an option added via `addOption()`.
|
|
278
|
+
*/
|
|
279
|
+
async resolveDecision(decisionUid, chosenOptionUid, opts) {
|
|
280
|
+
return this.post("/intent/deliberation", {
|
|
281
|
+
action: "resolve",
|
|
282
|
+
decision_uid: decisionUid,
|
|
283
|
+
chosen_option_uid: chosenOptionUid,
|
|
284
|
+
...opts
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
// ---- Action Layer ----
|
|
288
|
+
async procedure(req) {
|
|
289
|
+
return this.post("/action/procedure", req);
|
|
290
|
+
}
|
|
291
|
+
async risk(req) {
|
|
292
|
+
return this.post("/action/risk", req);
|
|
293
|
+
}
|
|
294
|
+
// ---- Memory Layer ----
|
|
295
|
+
async session(req) {
|
|
296
|
+
return this.post("/memory/session", req);
|
|
297
|
+
}
|
|
298
|
+
async journal(label, props, options) {
|
|
299
|
+
return this.post("/memory/session", {
|
|
300
|
+
action: "journal",
|
|
301
|
+
label,
|
|
302
|
+
props,
|
|
303
|
+
...options
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
async distill(req) {
|
|
307
|
+
return this.post("/memory/distill", req);
|
|
308
|
+
}
|
|
309
|
+
async memoryConfig(req) {
|
|
310
|
+
return this.post("/memory/config", req);
|
|
311
|
+
}
|
|
312
|
+
async memorySync(req) {
|
|
313
|
+
return this.post("/memory/sync", req);
|
|
314
|
+
}
|
|
315
|
+
// ---- Agent Layer ----
|
|
316
|
+
async plan(req) {
|
|
317
|
+
return this.post("/agent/plan", req);
|
|
318
|
+
}
|
|
319
|
+
async governance(req) {
|
|
320
|
+
return this.post("/agent/governance", req);
|
|
321
|
+
}
|
|
322
|
+
async execution(req) {
|
|
323
|
+
return this.post("/agent/execution", req);
|
|
324
|
+
}
|
|
325
|
+
// ---- Cross-cutting ----
|
|
326
|
+
/** Returns an array of results. Shape varies by action. */
|
|
327
|
+
async retrieve(req) {
|
|
328
|
+
return this.post("/retrieve", req);
|
|
329
|
+
}
|
|
330
|
+
async traverse(req) {
|
|
331
|
+
return this.post("/traverse", req);
|
|
332
|
+
}
|
|
333
|
+
async evolve(req) {
|
|
334
|
+
return this.post("/evolve", req);
|
|
335
|
+
}
|
|
336
|
+
// ---- Node CRUD ----
|
|
337
|
+
async getNode(uid) {
|
|
338
|
+
return this.get(`/node/${seg(uid)}`);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Create a node via the low-level CRUD endpoint.
|
|
342
|
+
*
|
|
343
|
+
* The server requires `props._type` to determine the node variant.
|
|
344
|
+
* If `node_type` is provided and `_type` is not already in `props`,
|
|
345
|
+
* it is injected automatically.
|
|
346
|
+
*/
|
|
347
|
+
async addNode(body) {
|
|
348
|
+
const props = { ...body.props };
|
|
349
|
+
if (body.node_type && !("_type" in props)) {
|
|
350
|
+
props._type = body.node_type;
|
|
351
|
+
}
|
|
352
|
+
return this.post("/node", { ...body, props });
|
|
353
|
+
}
|
|
354
|
+
async updateNode(uid, body) {
|
|
355
|
+
return this.patch(`/node/${seg(uid)}`, body);
|
|
356
|
+
}
|
|
357
|
+
async deleteNode(uid) {
|
|
358
|
+
await this.del(`/node/${seg(uid)}`);
|
|
359
|
+
}
|
|
360
|
+
async batchDeleteNodes(params) {
|
|
361
|
+
const body = {};
|
|
362
|
+
if (params.uids) body.uids = params.uids;
|
|
363
|
+
if (params.agentId) body.agent_id = params.agentId;
|
|
364
|
+
if (params.filter) {
|
|
365
|
+
body.filter = {
|
|
366
|
+
node_type: params.filter.nodeType,
|
|
367
|
+
node_types: params.filter.nodeTypes,
|
|
368
|
+
layer: params.filter.layer,
|
|
369
|
+
label_contains: params.filter.labelContains,
|
|
370
|
+
prop_equals: params.filter.propEquals
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
if (params.reason) body.reason = params.reason;
|
|
374
|
+
if (params.by) body.by = params.by;
|
|
375
|
+
if (params.hardPurge) body.hard_purge = params.hardPurge;
|
|
376
|
+
return this.post("/nodes/delete", body);
|
|
377
|
+
}
|
|
378
|
+
async getNodeHistory(uid) {
|
|
379
|
+
return this.get(`/node/${seg(uid)}/history`);
|
|
380
|
+
}
|
|
381
|
+
async getNodeAtVersion(uid, version) {
|
|
382
|
+
return this.get(`/node/${seg(uid)}/history/${seg(version)}`);
|
|
383
|
+
}
|
|
384
|
+
// ---- Edge CRUD ----
|
|
385
|
+
async addLink(body) {
|
|
386
|
+
return this.post("/link", body);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Create an edge via the low-level CRUD endpoint.
|
|
390
|
+
*
|
|
391
|
+
* The server requires `props._type` to determine the edge variant.
|
|
392
|
+
* If `edge_type` is provided and `_type` is not already in `props`,
|
|
393
|
+
* it is injected automatically.
|
|
394
|
+
*/
|
|
395
|
+
async addEdge(body) {
|
|
396
|
+
const props = { ...body.props };
|
|
397
|
+
if (body.edge_type && !("_type" in props)) {
|
|
398
|
+
props._type = body.edge_type;
|
|
399
|
+
}
|
|
400
|
+
return this.post("/edge", { ...body, props });
|
|
401
|
+
}
|
|
402
|
+
async updateEdge(uid, body) {
|
|
403
|
+
return this.patch(`/edge/${seg(uid)}`, body);
|
|
404
|
+
}
|
|
405
|
+
async deleteEdge(uid) {
|
|
406
|
+
await this.del(`/edge/${seg(uid)}`);
|
|
407
|
+
}
|
|
408
|
+
async getEdgeHistory(uid) {
|
|
409
|
+
return this.get(`/edge/${seg(uid)}/history`);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* List edges filtered by source and/or target node.
|
|
413
|
+
* At least one of `from_uid` or `to_uid` is **required** —
|
|
414
|
+
* the server returns 400 if neither is provided.
|
|
415
|
+
*/
|
|
416
|
+
async getEdges(params) {
|
|
417
|
+
if (!params.from_uid && !params.to_uid) {
|
|
418
|
+
throw new Error("at least one of from_uid or to_uid is required");
|
|
419
|
+
}
|
|
420
|
+
const qs = new URLSearchParams();
|
|
421
|
+
if (params.from_uid) qs.set("from_uid", params.from_uid);
|
|
422
|
+
if (params.to_uid) qs.set("to_uid", params.to_uid);
|
|
423
|
+
return this.get(`/edges?${qs}`);
|
|
424
|
+
}
|
|
425
|
+
async getEdgeBetween(params) {
|
|
426
|
+
const qs = new URLSearchParams();
|
|
427
|
+
qs.set("from_uid", params.from_uid);
|
|
428
|
+
qs.set("to_uid", params.to_uid);
|
|
429
|
+
if (params.edge_type) qs.set("edge_type", params.edge_type);
|
|
430
|
+
return this.get(`/edge/between?${qs}`);
|
|
431
|
+
}
|
|
432
|
+
// ---- Search ----
|
|
433
|
+
async search(query, opts) {
|
|
434
|
+
return this.post("/search", { query, ...opts });
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Hybrid BM25 + vector search with reciprocal rank fusion. Pass
|
|
438
|
+
* `explain: true` to get per-leg contributions (`legs`) on each result —
|
|
439
|
+
* the "why retrieved" detail (server ≥ 1.2.0; older servers ignore it).
|
|
440
|
+
*/
|
|
441
|
+
async hybridSearch(query, opts) {
|
|
442
|
+
return this.post("/retrieve", {
|
|
443
|
+
action: "hybrid",
|
|
444
|
+
query,
|
|
445
|
+
...opts
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
// ---- Nodes listing ----
|
|
449
|
+
async getNodes(params) {
|
|
450
|
+
const qs = new URLSearchParams();
|
|
451
|
+
if (params?.node_type) qs.set("node_type", params.node_type);
|
|
452
|
+
if (params?.layer) qs.set("layer", params.layer);
|
|
453
|
+
if (params?.limit != null) qs.set("limit", String(params.limit));
|
|
454
|
+
if (params?.offset != null) qs.set("offset", String(params.offset));
|
|
455
|
+
return this.get(`/nodes?${qs}`);
|
|
456
|
+
}
|
|
457
|
+
async getAgentNodes(agentId) {
|
|
458
|
+
return this.get(`/agent/${seg(agentId)}/nodes`);
|
|
459
|
+
}
|
|
460
|
+
// ---- Batch ----
|
|
461
|
+
async batch(req) {
|
|
462
|
+
return this.post("/batch", req);
|
|
463
|
+
}
|
|
464
|
+
/** Fetch multiple nodes by UID in a single request. */
|
|
465
|
+
async getNodesBatch(uids) {
|
|
466
|
+
return this.post("/nodes/batch", { uids });
|
|
467
|
+
}
|
|
468
|
+
/** Fetch all edges between a set of node UIDs. */
|
|
469
|
+
async getEdgesBatch(uids) {
|
|
470
|
+
return this.post("/edges/batch", { uids });
|
|
471
|
+
}
|
|
472
|
+
// ---- Embeddings ----
|
|
473
|
+
async configureEmbeddings(body) {
|
|
474
|
+
return this.post("/embeddings/configure", body);
|
|
475
|
+
}
|
|
476
|
+
async embeddingSearch(body) {
|
|
477
|
+
return this.post("/embeddings/search", body);
|
|
478
|
+
}
|
|
479
|
+
async embeddingSearchText(body) {
|
|
480
|
+
return this.post("/embeddings/search-text", body);
|
|
481
|
+
}
|
|
482
|
+
async getEmbedding(uid) {
|
|
483
|
+
return this.get(`/node/${seg(uid)}/embedding`);
|
|
484
|
+
}
|
|
485
|
+
async setEmbedding(uid, vector) {
|
|
486
|
+
await this.request("PUT", `/node/${seg(uid)}/embedding`, { vector });
|
|
487
|
+
}
|
|
488
|
+
async deleteEmbedding(uid) {
|
|
489
|
+
await this.del(`/node/${seg(uid)}/embedding`);
|
|
490
|
+
}
|
|
491
|
+
// ---- Entity resolution ----
|
|
492
|
+
async mergeEntities(body) {
|
|
493
|
+
return this.post("/entities/merge", body);
|
|
494
|
+
}
|
|
495
|
+
async addAlias(body) {
|
|
496
|
+
return this.post("/alias", body);
|
|
497
|
+
}
|
|
498
|
+
async getAliases(uid) {
|
|
499
|
+
return this.get(`/aliases/${seg(uid)}`);
|
|
500
|
+
}
|
|
501
|
+
async resolveAlias(text) {
|
|
502
|
+
return this.get(`/resolve?text=${encodeURIComponent(text)}`);
|
|
503
|
+
}
|
|
504
|
+
// ---- Export / Import ----
|
|
505
|
+
async exportGraph() {
|
|
506
|
+
return this.get("/export");
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Export one document's extraction provenance as JSON-LD: PROV-O
|
|
510
|
+
* entities/agents, CiTO relations between extracted claims, and the
|
|
511
|
+
* citation anchors as W3C Web Annotations (TextQuoteSelector +
|
|
512
|
+
* TextPositionSelector; positions are chunk-relative UTF-8 byte offsets,
|
|
513
|
+
* flagged via `mg:offsetUnit`).
|
|
514
|
+
*/
|
|
515
|
+
async exportProvenance(documentUid) {
|
|
516
|
+
return this.get(
|
|
517
|
+
`/export/prov?document_uid=${encodeURIComponent(documentUid)}`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
async importGraph(data) {
|
|
521
|
+
return this.post("/import", data);
|
|
522
|
+
}
|
|
523
|
+
// ---- Lifecycle ----
|
|
524
|
+
async decay(req) {
|
|
525
|
+
return this.post("/decay", req);
|
|
526
|
+
}
|
|
527
|
+
async purge(req) {
|
|
528
|
+
return this.post("/purge", req ?? {});
|
|
529
|
+
}
|
|
530
|
+
// ---- Traversal shortcuts ----
|
|
531
|
+
async reasoningChain(uid, maxDepth = 5) {
|
|
532
|
+
const r = await this.post("/traverse", {
|
|
533
|
+
action: "chain",
|
|
534
|
+
start_uid: uid,
|
|
535
|
+
max_depth: maxDepth
|
|
536
|
+
});
|
|
537
|
+
return r?.steps ?? r;
|
|
538
|
+
}
|
|
539
|
+
async neighborhood(uid, maxDepth = 1) {
|
|
540
|
+
const r = await this.post("/traverse", {
|
|
541
|
+
action: "neighborhood",
|
|
542
|
+
start_uid: uid,
|
|
543
|
+
max_depth: maxDepth
|
|
544
|
+
});
|
|
545
|
+
return r?.steps ?? r;
|
|
546
|
+
}
|
|
547
|
+
async subgraph(uid, opts) {
|
|
548
|
+
return this.post("/subgraph", { start_uids: [uid], ...opts });
|
|
549
|
+
}
|
|
550
|
+
// ---- Lifecycle shortcuts ----
|
|
551
|
+
async tombstone(uid, reason, agentId) {
|
|
552
|
+
return this.post("/evolve", {
|
|
553
|
+
action: "tombstone",
|
|
554
|
+
uid,
|
|
555
|
+
reason,
|
|
556
|
+
agent_id: agentId
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
async restore(uid, agentId) {
|
|
560
|
+
return this.post("/evolve", {
|
|
561
|
+
action: "restore",
|
|
562
|
+
uid,
|
|
563
|
+
agent_id: agentId
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
// ---- Epistemic queries ----
|
|
567
|
+
async getGoals() {
|
|
568
|
+
return this.get("/goals");
|
|
569
|
+
}
|
|
570
|
+
async getOpenDecisions() {
|
|
571
|
+
return this.get("/decisions");
|
|
572
|
+
}
|
|
573
|
+
async getOpenQuestions() {
|
|
574
|
+
return this.get("/questions");
|
|
575
|
+
}
|
|
576
|
+
async getWeakClaims() {
|
|
577
|
+
return this.get("/claims/weak");
|
|
578
|
+
}
|
|
579
|
+
async getContradictions() {
|
|
580
|
+
return this.get("/contradictions");
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Pending merge candidates: suspected duplicate pairs recorded by the dedup
|
|
584
|
+
* pipeline's ambiguous zone as PossibleDuplicate edges, awaiting a human
|
|
585
|
+
* merge/dismiss decision (server >= 1.3).
|
|
586
|
+
*/
|
|
587
|
+
async getMergeCandidates() {
|
|
588
|
+
return this.post("/retrieve", { action: "merge_candidates" });
|
|
589
|
+
}
|
|
590
|
+
/** Load-bearing conclusions awaiting repair after a premise changed. */
|
|
591
|
+
async getStaleDerivations(limit = 50, offset = 0) {
|
|
592
|
+
return this.post("/retrieve", { action: "stale_derivations", limit, offset });
|
|
593
|
+
}
|
|
594
|
+
async getPendingApprovals() {
|
|
595
|
+
return this.get("/approvals/pending");
|
|
596
|
+
}
|
|
597
|
+
// ---- Ingestion & Retrieval ----
|
|
598
|
+
async ingestChunk(req) {
|
|
599
|
+
return this.post("/ingest/chunk", req);
|
|
600
|
+
}
|
|
601
|
+
async ingestDocument(req) {
|
|
602
|
+
return this.post("/ingest/document", req);
|
|
603
|
+
}
|
|
604
|
+
async ingestSession(req) {
|
|
605
|
+
return this.post("/ingest/session", req);
|
|
606
|
+
}
|
|
607
|
+
async retrieveContext(req) {
|
|
608
|
+
return this.post("/retrieve/context", req);
|
|
609
|
+
}
|
|
610
|
+
/** Backfill node_source provenance for existing graphs. */
|
|
611
|
+
async backfillNodeSources() {
|
|
612
|
+
return this.post("/backfill/node-sources", {});
|
|
613
|
+
}
|
|
614
|
+
/** Backfill citation anchors (source_chunks spans) for existing graphs. Returns a background job id. */
|
|
615
|
+
async backfillAnchors() {
|
|
616
|
+
return this.post("/backfill/anchors", {});
|
|
617
|
+
}
|
|
618
|
+
async listJobs() {
|
|
619
|
+
return this.get("/jobs");
|
|
620
|
+
}
|
|
621
|
+
async getJob(id) {
|
|
622
|
+
return this.get(`/jobs/${seg(id)}`);
|
|
623
|
+
}
|
|
624
|
+
async cancelJob(id) {
|
|
625
|
+
return this.post(`/jobs/${seg(id)}/cancel`, {});
|
|
626
|
+
}
|
|
627
|
+
/** Resume ingestion of a document that has failed chunks. */
|
|
628
|
+
async resumeDocument(docUid, opts) {
|
|
629
|
+
return this.post(`/ingest/resume/${seg(docUid)}`, opts ?? {});
|
|
630
|
+
}
|
|
631
|
+
/** Delete a document and all its chunks and extracted nodes. */
|
|
632
|
+
async deleteDocument(uid) {
|
|
633
|
+
return this.del(`/ingest/document/${seg(uid)}`);
|
|
634
|
+
}
|
|
635
|
+
async cleanupOrphans() {
|
|
636
|
+
return this.post("/ingest/cleanup", {});
|
|
637
|
+
}
|
|
638
|
+
async embedAll() {
|
|
639
|
+
return this.post("/ingest/embed-all", {});
|
|
640
|
+
}
|
|
641
|
+
async clearGraph() {
|
|
642
|
+
return this.post("/clear", {});
|
|
643
|
+
}
|
|
644
|
+
// ── Wiki ──────────────────────────────────────────────────────────────
|
|
645
|
+
/** List wiki articles with optional filters. */
|
|
646
|
+
async listArticles(params) {
|
|
647
|
+
const q = new URLSearchParams();
|
|
648
|
+
if (params?.article_type) q.set("article_type", params.article_type);
|
|
649
|
+
if (params?.covers_node_type) q.set("covers_node_type", params.covers_node_type);
|
|
650
|
+
if (params?.search) q.set("search", params.search);
|
|
651
|
+
if (params?.limit) q.set("limit", String(params.limit));
|
|
652
|
+
if (params?.offset) q.set("offset", String(params.offset));
|
|
653
|
+
return this.get(`/wiki/articles?${q}`);
|
|
654
|
+
}
|
|
655
|
+
/** Get a single wiki article by UID. */
|
|
656
|
+
async getArticle(uid) {
|
|
657
|
+
return this.get(`/wiki/article/${seg(uid)}`);
|
|
658
|
+
}
|
|
659
|
+
/** Find the article that covers or summarizes a given entity/document UID. */
|
|
660
|
+
async getArticleBySubject(subjectUid) {
|
|
661
|
+
try {
|
|
662
|
+
return await this.get(`/wiki/article/by-subject/${seg(subjectUid)}`);
|
|
663
|
+
} catch {
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/** Update an article's markdown content (user editing). */
|
|
668
|
+
async updateArticle(uid, content) {
|
|
669
|
+
return this.patch(`/wiki/article/${seg(uid)}`, { content });
|
|
670
|
+
}
|
|
671
|
+
/** Trigger wiki compilation for a specific document. */
|
|
672
|
+
async compileDocument(docUid) {
|
|
673
|
+
return this.post(`/wiki/compile/${seg(docUid)}`, {});
|
|
674
|
+
}
|
|
675
|
+
/** Trigger wiki compilation for a specific entity. */
|
|
676
|
+
async compileEntity(entityUid) {
|
|
677
|
+
return this.post(`/wiki/compile/entity/${seg(entityUid)}`, {});
|
|
678
|
+
}
|
|
679
|
+
/** Backfill: compile articles for all documents and eligible entities. */
|
|
680
|
+
async compileAll() {
|
|
681
|
+
return this.post("/wiki/compile/all", {});
|
|
682
|
+
}
|
|
683
|
+
// ── Synthesis (Projects) ──────────────────────────────────────────────
|
|
684
|
+
/**
|
|
685
|
+
* Mine structural synthesis signals for a project's document corpus.
|
|
686
|
+
*
|
|
687
|
+
* Returns candidate surface for downstream synthesis — entity bridges
|
|
688
|
+
* across documents, claim hubs, clustered claim hubs, theory support
|
|
689
|
+
* gaps, concept clusters, analogy candidates, and dialectical pairs.
|
|
690
|
+
*
|
|
691
|
+
* Blocking operation. No LLM calls; Datalog + embedding clustering only.
|
|
692
|
+
*/
|
|
693
|
+
async signals(projectUid, opts) {
|
|
694
|
+
const q = new URLSearchParams();
|
|
695
|
+
if (opts?.signals) q.set("signals", opts.signals);
|
|
696
|
+
if (opts?.target_types) q.set("target_types", opts.target_types);
|
|
697
|
+
const qs = q.toString();
|
|
698
|
+
return this.get(`/synthesis/signals/${seg(projectUid)}${qs ? `?${qs}` : ""}`);
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Spawn a background synthesis job for a project: mines signals,
|
|
702
|
+
* selects top idea clusters, runs LLM synthesis, and persists
|
|
703
|
+
* candidate Article nodes linked via `Covers` edges.
|
|
704
|
+
*
|
|
705
|
+
* Returns a `job_id` immediately; poll `getJob(id)` for progress.
|
|
706
|
+
*/
|
|
707
|
+
async runSynthesis(projectUid) {
|
|
708
|
+
return this.post(`/synthesis/run/${seg(projectUid)}`, {});
|
|
709
|
+
}
|
|
710
|
+
// ============================================================================
|
|
711
|
+
// Operational Ontology Layer (Layer 7)
|
|
712
|
+
// ============================================================================
|
|
713
|
+
// ---- Schema management (cloud Postgres) ----
|
|
714
|
+
async listOntologySchemas() {
|
|
715
|
+
return this.get("/v1/ontology/schemas");
|
|
716
|
+
}
|
|
717
|
+
async getOntologySchema(id) {
|
|
718
|
+
return this.get(`/v1/ontology/schemas/${seg(id)}`);
|
|
719
|
+
}
|
|
720
|
+
async createOntologySchema(req) {
|
|
721
|
+
return this.post("/v1/ontology/schemas", req);
|
|
722
|
+
}
|
|
723
|
+
async updateOntologySchema(id, req) {
|
|
724
|
+
return this.patch(`/v1/ontology/schemas/${seg(id)}`, req);
|
|
725
|
+
}
|
|
726
|
+
async activateOntologySchema(id) {
|
|
727
|
+
return this.post(`/v1/ontology/schemas/${seg(id)}/activate`, {});
|
|
728
|
+
}
|
|
729
|
+
async deprecateOntologySchema(id) {
|
|
730
|
+
return this.post(`/v1/ontology/schemas/${seg(id)}/deprecate`, {});
|
|
731
|
+
}
|
|
732
|
+
async archiveOntologySchema(id) {
|
|
733
|
+
return this.del(`/v1/ontology/schemas/${seg(id)}`);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Kick off an LLM-driven schema proposal job.
|
|
737
|
+
* Returns immediately with `{ schema_id, job_id }`; poll
|
|
738
|
+
* `getOntologySchema(schema_id)` for streaming progress.
|
|
739
|
+
*/
|
|
740
|
+
async proposeOntologySchema(req) {
|
|
741
|
+
return this.post("/v1/ontology/propose-schema", req);
|
|
742
|
+
}
|
|
743
|
+
async testOntologySchema(id, opts) {
|
|
744
|
+
return this.post(`/v1/ontology/schemas/${seg(id)}/test`, opts ?? {});
|
|
745
|
+
}
|
|
746
|
+
// ---- Schema sub-resources ----
|
|
747
|
+
async addOntologyObjectType(schemaId, req) {
|
|
748
|
+
return this.post(`/v1/ontology/schemas/${seg(schemaId)}/object-types`, req);
|
|
749
|
+
}
|
|
750
|
+
async updateOntologyObjectType(schemaId, typeId, req) {
|
|
751
|
+
return this.patch(
|
|
752
|
+
`/v1/ontology/schemas/${seg(schemaId)}/object-types/${seg(typeId)}`,
|
|
753
|
+
req
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
async deleteOntologyObjectType(schemaId, typeId) {
|
|
757
|
+
return this.del(
|
|
758
|
+
`/v1/ontology/schemas/${seg(schemaId)}/object-types/${seg(typeId)}`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
async addOntologyRelationType(schemaId, req) {
|
|
762
|
+
return this.post(`/v1/ontology/schemas/${seg(schemaId)}/relation-types`, req);
|
|
763
|
+
}
|
|
764
|
+
async updateOntologyRelationType(schemaId, typeId, req) {
|
|
765
|
+
return this.patch(
|
|
766
|
+
`/v1/ontology/schemas/${seg(schemaId)}/relation-types/${seg(typeId)}`,
|
|
767
|
+
req
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
async deleteOntologyRelationType(schemaId, typeId) {
|
|
771
|
+
return this.del(
|
|
772
|
+
`/v1/ontology/schemas/${seg(schemaId)}/relation-types/${seg(typeId)}`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
/** Generate inert semantic classifications for individual human review. */
|
|
776
|
+
async analyzeOntologySemanticGuidance(schemaId) {
|
|
777
|
+
return this.post(
|
|
778
|
+
`/v1/ontology/schemas/${seg(schemaId)}/semantic-guidance/analyze`,
|
|
779
|
+
{}
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
/** Read-only exact-identity collision audit; never merges graph data. */
|
|
783
|
+
async auditOntologyDuplicates(schemaId) {
|
|
784
|
+
return this.post(`/v1/ontology/schemas/${seg(schemaId)}/duplicates/audit`, {});
|
|
785
|
+
}
|
|
786
|
+
// ---- Proposals ----
|
|
787
|
+
async listOntologyProposals(opts) {
|
|
788
|
+
const q = new URLSearchParams();
|
|
789
|
+
if (opts?.status) q.set("status", opts.status);
|
|
790
|
+
if (opts?.schema_id) q.set("schema_id", opts.schema_id);
|
|
791
|
+
if (opts?.object_type) q.set("object_type", opts.object_type);
|
|
792
|
+
if (opts?.proposal_type) q.set("proposal_type", opts.proposal_type);
|
|
793
|
+
if (opts?.extract_job_id) q.set("extract_job_id", opts.extract_job_id);
|
|
794
|
+
if (opts?.limit != null) q.set("limit", String(opts.limit));
|
|
795
|
+
if (opts?.offset != null) q.set("offset", String(opts.offset));
|
|
796
|
+
const qs = q.toString();
|
|
797
|
+
return this.get(`/v1/ontology/proposals${qs ? `?${qs}` : ""}`);
|
|
798
|
+
}
|
|
799
|
+
async getOntologyProposal(id) {
|
|
800
|
+
return this.get(`/v1/ontology/proposals/${seg(id)}`);
|
|
801
|
+
}
|
|
802
|
+
async patchOntologyProposal(id, req) {
|
|
803
|
+
return this.patch(`/v1/ontology/proposals/${seg(id)}`, req);
|
|
804
|
+
}
|
|
805
|
+
async approveOntologyProposal(id, opts) {
|
|
806
|
+
return this.post(`/v1/ontology/proposals/${seg(id)}/approve`, opts ?? {});
|
|
807
|
+
}
|
|
808
|
+
async rejectOntologyProposal(id, reason) {
|
|
809
|
+
return this.post(`/v1/ontology/proposals/${seg(id)}/reject`, { reason });
|
|
810
|
+
}
|
|
811
|
+
async applyOntologyProposal(id) {
|
|
812
|
+
return this.post(`/v1/ontology/proposals/${seg(id)}/apply`, {});
|
|
813
|
+
}
|
|
814
|
+
async batchApproveOntologyProposals(ids, feedback) {
|
|
815
|
+
return this.post("/v1/ontology/proposals/batch-approve", { ids, feedback });
|
|
816
|
+
}
|
|
817
|
+
async batchRejectOntologyProposals(ids, reason) {
|
|
818
|
+
return this.post("/v1/ontology/proposals/batch-reject", { ids, reason });
|
|
819
|
+
}
|
|
820
|
+
// ---- Retrieval (graph server) ----
|
|
821
|
+
async queryOntology(req) {
|
|
822
|
+
return this.post("/ontology/query", req);
|
|
823
|
+
}
|
|
824
|
+
async queryDomainStructured(req) {
|
|
825
|
+
return this.post("/ontology/query/structured", req);
|
|
826
|
+
}
|
|
827
|
+
async queryRelatedDomainObjects(req) {
|
|
828
|
+
return this.queryDomainStructured({
|
|
829
|
+
schema_id: req.schema_id,
|
|
830
|
+
select: req.far_type,
|
|
831
|
+
...req.project_uid ? { project_uid: req.project_uid } : {},
|
|
832
|
+
anchor: { type: req.entry_type, uid: req.uid },
|
|
833
|
+
path: [{
|
|
834
|
+
relation: req.relation,
|
|
835
|
+
entry_role: req.entry_role
|
|
836
|
+
}],
|
|
837
|
+
...req.where ? { where: req.where } : {},
|
|
838
|
+
...req.include_provenance ? { include: { provenance: true } } : {},
|
|
839
|
+
page: {
|
|
840
|
+
...req.limit != null ? { limit: req.limit } : {},
|
|
841
|
+
...req.offset != null ? { offset: req.offset } : {}
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Schema-qualified read-tool descriptors generated from every active
|
|
847
|
+
* ontology. Includes per-object discovery/point/context tools,
|
|
848
|
+
* relation-and-role-specific related tools, and one structured composite.
|
|
849
|
+
*/
|
|
850
|
+
async listOntologyTools() {
|
|
851
|
+
return this.get("/v1/ontology/tools");
|
|
852
|
+
}
|
|
853
|
+
async getDomainObject(uid, binding) {
|
|
854
|
+
const query = new URLSearchParams();
|
|
855
|
+
if (binding) {
|
|
856
|
+
query.set("schema_id", binding.schema_id);
|
|
857
|
+
query.set("object_type", binding.object_type);
|
|
858
|
+
if (binding.project_uid) query.set("project_uid", binding.project_uid);
|
|
859
|
+
}
|
|
860
|
+
const suffix = query.size > 0 ? `?${query.toString()}` : "";
|
|
861
|
+
return this.get(`/ontology/object/${seg(uid)}${suffix}`);
|
|
862
|
+
}
|
|
863
|
+
async getDomainObjectContext(uid, depth, binding) {
|
|
864
|
+
const query = new URLSearchParams();
|
|
865
|
+
if (depth != null) query.set("depth", String(depth));
|
|
866
|
+
if (binding) {
|
|
867
|
+
query.set("schema_id", binding.schema_id);
|
|
868
|
+
query.set("object_type", binding.object_type);
|
|
869
|
+
if (binding.project_uid) query.set("project_uid", binding.project_uid);
|
|
870
|
+
}
|
|
871
|
+
const suffix = query.size > 0 ? `?${query.toString()}` : "";
|
|
872
|
+
return this.get(`/ontology/object/${seg(uid)}/context${suffix}`);
|
|
873
|
+
}
|
|
874
|
+
async getDomainObjectHistory(uid) {
|
|
875
|
+
return this.get(`/ontology/object/${seg(uid)}/history`);
|
|
876
|
+
}
|
|
877
|
+
async listDomainObjects(opts) {
|
|
878
|
+
const q = new URLSearchParams();
|
|
879
|
+
q.set("schema_id", opts.schema_id);
|
|
880
|
+
if (opts.object_type) q.set("object_type", opts.object_type);
|
|
881
|
+
if (opts.limit != null) q.set("limit", String(opts.limit));
|
|
882
|
+
if (opts.offset != null) q.set("offset", String(opts.offset));
|
|
883
|
+
if (opts.sort) q.set("sort", opts.sort);
|
|
884
|
+
return this.get(`/ontology/objects?${q.toString()}`);
|
|
885
|
+
}
|
|
886
|
+
async searchDomainObjects(query, opts) {
|
|
887
|
+
return this.post("/ontology/objects/search", { query, ...opts ?? {} });
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Per-object-type coverage stats for a schema (C2f): field fill rates
|
|
891
|
+
* (with a `near_empty` flag < 5%) and identity collisions, over a bounded
|
|
892
|
+
* per-type sample (default 500, max 2000).
|
|
893
|
+
*/
|
|
894
|
+
async ontologyStats(schemaId, sample) {
|
|
895
|
+
const q = new URLSearchParams({ schema_id: schemaId });
|
|
896
|
+
if (sample != null) q.set("sample", String(sample));
|
|
897
|
+
return this.get(`/ontology/stats?${q.toString()}`);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Create a domain object by hand (auto-approved). Returns the created node
|
|
901
|
+
* uid + the audit proposal id. Throws 409 if an object of the same type +
|
|
902
|
+
* canonical_name already exists, unless `allow_duplicate` is set.
|
|
903
|
+
*/
|
|
904
|
+
async createDomainObject(req) {
|
|
905
|
+
return this.post("/v1/ontology/objects", req);
|
|
906
|
+
}
|
|
907
|
+
async linkDomainObjects(req) {
|
|
908
|
+
return this.post("/ontology/relation", { action: "create", ...req });
|
|
909
|
+
}
|
|
910
|
+
// ---- Extraction ----
|
|
911
|
+
async extractOntology(req) {
|
|
912
|
+
return this.post("/ontology/extract", req);
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
29
918
|
// src/codegraph.ts
|
|
30
919
|
function normalizePath(path6) {
|
|
31
920
|
return path6.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
@@ -712,17 +1601,16 @@ var init_codegraph = __esm({
|
|
|
712
1601
|
|
|
713
1602
|
// src/error-detail.ts
|
|
714
1603
|
function errorDetail(e) {
|
|
715
|
-
if (e instanceof
|
|
1604
|
+
if (e instanceof MindGraphError && e.body !== void 0) {
|
|
716
1605
|
const detail = typeof e.body === "string" ? e.body : JSON.stringify(e.body);
|
|
717
1606
|
return `${e.message} \u2014 ${detail}`;
|
|
718
1607
|
}
|
|
719
1608
|
return e instanceof Error ? e.message : String(e);
|
|
720
1609
|
}
|
|
721
|
-
var import_mindgraph;
|
|
722
1610
|
var init_error_detail = __esm({
|
|
723
1611
|
"src/error-detail.ts"() {
|
|
724
1612
|
"use strict";
|
|
725
|
-
|
|
1613
|
+
init_dist();
|
|
726
1614
|
}
|
|
727
1615
|
});
|
|
728
1616
|
|
|
@@ -3874,14 +4762,14 @@ async function main() {
|
|
|
3874
4762
|
`MindGraph MCP server v0.7.1 running on stdio (${BASE_URL})`
|
|
3875
4763
|
);
|
|
3876
4764
|
}
|
|
3877
|
-
var import_server, import_stdio, import_types,
|
|
4765
|
+
var import_server, import_stdio, import_types, API_KEY, BASE_URL, AGENT_ID, ORG_ID, PROFILE, HARNESS, client, INSTRUCTIONS, server, GOVERNANCE_CONFIG, PROMPTS;
|
|
3878
4766
|
var init_src = __esm({
|
|
3879
4767
|
"src/index.ts"() {
|
|
3880
4768
|
"use strict";
|
|
3881
4769
|
import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
3882
4770
|
import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
3883
4771
|
import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
3884
|
-
|
|
4772
|
+
init_dist();
|
|
3885
4773
|
init_tools();
|
|
3886
4774
|
init_generated_tools();
|
|
3887
4775
|
init_governance();
|
|
@@ -3898,7 +4786,7 @@ var init_src = __esm({
|
|
|
3898
4786
|
);
|
|
3899
4787
|
process.exit(1);
|
|
3900
4788
|
}
|
|
3901
|
-
client = new
|
|
4789
|
+
client = new MindGraph({
|
|
3902
4790
|
baseUrl: BASE_URL,
|
|
3903
4791
|
apiKey: API_KEY,
|
|
3904
4792
|
orgId: ORG_ID,
|
|
@@ -4005,7 +4893,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
4005
4893
|
server = new import_server.Server(
|
|
4006
4894
|
{
|
|
4007
4895
|
name: "mindgraph",
|
|
4008
|
-
version: "0.14.
|
|
4896
|
+
version: "0.14.3"
|
|
4009
4897
|
},
|
|
4010
4898
|
{
|
|
4011
4899
|
capabilities: {
|
|
@@ -4228,7 +5116,7 @@ var path5 = __toESM(require("path"));
|
|
|
4228
5116
|
var os4 = __toESM(require("os"));
|
|
4229
5117
|
var crypto4 = __toESM(require("crypto"));
|
|
4230
5118
|
var import_child_process = require("child_process");
|
|
4231
|
-
|
|
5119
|
+
init_dist();
|
|
4232
5120
|
|
|
4233
5121
|
// src/hook-env.ts
|
|
4234
5122
|
var import_node_fs = __toESM(require("fs"));
|
|
@@ -4317,6 +5205,17 @@ function parseArgs(argv) {
|
|
|
4317
5205
|
}
|
|
4318
5206
|
return { command, apiKey, baseUrl, scope, projectDir, harness, hooks };
|
|
4319
5207
|
}
|
|
5208
|
+
function mcpAddFailureOutput(e) {
|
|
5209
|
+
const err5 = e;
|
|
5210
|
+
return `${err5.stdout ?? ""}${err5.stderr ?? ""}`.trim();
|
|
5211
|
+
}
|
|
5212
|
+
function classifyMcpAddFailure(e) {
|
|
5213
|
+
if (e?.code === "ENOENT") return "missing-cli";
|
|
5214
|
+
if (mcpAddFailureOutput(e).toLowerCase().includes("already exists")) {
|
|
5215
|
+
return "already-exists";
|
|
5216
|
+
}
|
|
5217
|
+
return "other";
|
|
5218
|
+
}
|
|
4320
5219
|
|
|
4321
5220
|
// src/claude-hooks.ts
|
|
4322
5221
|
var import_node_crypto2 = __toESM(require("crypto"));
|
|
@@ -4829,19 +5728,21 @@ function installClaudeHooks(scope, projectDir = process.cwd()) {
|
|
|
4829
5728
|
const settings = readSettings(file);
|
|
4830
5729
|
const hooks = settings.hooks && typeof settings.hooks === "object" && !Array.isArray(settings.hooks) ? settings.hooks : {};
|
|
4831
5730
|
let added = 0;
|
|
5731
|
+
let updated = 0;
|
|
4832
5732
|
for (const [event, wanted] of Object.entries(desiredEntries())) {
|
|
4833
5733
|
const current = Array.isArray(hooks[event]) ? [...hooks[event]] : [];
|
|
5734
|
+
const kept = current.filter((entry) => !entryHasOwnedHook(entry));
|
|
5735
|
+
const hadOwned = kept.length !== current.length;
|
|
4834
5736
|
for (const entry of wanted) {
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
}
|
|
5737
|
+
kept.push(entry);
|
|
5738
|
+
if (hadOwned) updated += 1;
|
|
5739
|
+
else added += 1;
|
|
4839
5740
|
}
|
|
4840
|
-
hooks[event] =
|
|
5741
|
+
hooks[event] = kept;
|
|
4841
5742
|
}
|
|
4842
5743
|
settings.hooks = hooks;
|
|
4843
5744
|
writeSettings(file, settings);
|
|
4844
|
-
return { path: file, added };
|
|
5745
|
+
return { path: file, added, updated };
|
|
4845
5746
|
}
|
|
4846
5747
|
function uninstallClaudeHooks(scope, projectDir = process.cwd()) {
|
|
4847
5748
|
const file = settingsPath(scope, projectDir);
|
|
@@ -4962,7 +5863,7 @@ function installClaudeCode(apiKey, baseUrl) {
|
|
|
4962
5863
|
envArgs.push("--env", `MINDGRAPH_BASE_URL=${baseUrl}`);
|
|
4963
5864
|
}
|
|
4964
5865
|
try {
|
|
4965
|
-
(0, import_child_process.execFileSync)(
|
|
5866
|
+
const out = (0, import_child_process.execFileSync)(
|
|
4966
5867
|
"claude",
|
|
4967
5868
|
[
|
|
4968
5869
|
"mcp",
|
|
@@ -4974,15 +5875,30 @@ function installClaudeCode(apiKey, baseUrl) {
|
|
|
4974
5875
|
"-y",
|
|
4975
5876
|
"mindgraph-mcp@latest"
|
|
4976
5877
|
],
|
|
4977
|
-
{ stdio: "inherit" }
|
|
5878
|
+
{ stdio: ["inherit", "pipe", "pipe"] }
|
|
4978
5879
|
);
|
|
5880
|
+
if (out?.length) process.stdout.write(out);
|
|
4979
5881
|
console.log("Added MindGraph MCP server to Claude Code.");
|
|
4980
|
-
} catch {
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
5882
|
+
} catch (e) {
|
|
5883
|
+
switch (classifyMcpAddFailure(e)) {
|
|
5884
|
+
case "already-exists":
|
|
5885
|
+
console.log(
|
|
5886
|
+
"MindGraph MCP server already registered in Claude Code \u2014 leaving it in place."
|
|
5887
|
+
);
|
|
5888
|
+
break;
|
|
5889
|
+
case "missing-cli":
|
|
5890
|
+
console.error(
|
|
5891
|
+
"Failed to run 'claude mcp add'. Is Claude Code CLI installed?"
|
|
5892
|
+
);
|
|
5893
|
+
console.error("Install it from: https://claude.ai/code");
|
|
5894
|
+
process.exit(1);
|
|
5895
|
+
break;
|
|
5896
|
+
default: {
|
|
5897
|
+
const detail = mcpAddFailureOutput(e);
|
|
5898
|
+
console.error(detail || "'claude mcp add' failed.");
|
|
5899
|
+
process.exit(1);
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
4986
5902
|
}
|
|
4987
5903
|
}
|
|
4988
5904
|
function uninstallClaudeDesktop() {
|
|
@@ -5041,7 +5957,7 @@ function finishCodeInstall(apiKey, baseUrl, withHooks) {
|
|
|
5041
5957
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
5042
5958
|
const result = installClaudeHooks("user");
|
|
5043
5959
|
console.log(
|
|
5044
|
-
`Installed ${result.added} MindGraph Claude Code hook entries in ${result.path}`
|
|
5960
|
+
`Installed ${result.added} and refreshed ${result.updated} MindGraph Claude Code hook entries in ${result.path}`
|
|
5045
5961
|
);
|
|
5046
5962
|
const envPath = saveHookEnv({ apiKey, baseUrl });
|
|
5047
5963
|
console.log(`Saved hook connection settings to ${envPath} (mode 600)`);
|
|
@@ -5251,7 +6167,7 @@ async function main2() {
|
|
|
5251
6167
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
5252
6168
|
const result = installClaudeHooks(scope, projectDir);
|
|
5253
6169
|
console.log(
|
|
5254
|
-
`Installed ${result.added} MindGraph Claude Code hook entries in ${result.path}`
|
|
6170
|
+
`Installed ${result.added} and refreshed ${result.updated} MindGraph Claude Code hook entries in ${result.path}`
|
|
5255
6171
|
);
|
|
5256
6172
|
if (apiKey || baseUrl) {
|
|
5257
6173
|
const envPath = saveHookEnv({ apiKey, baseUrl });
|
|
@@ -5284,7 +6200,7 @@ async function main2() {
|
|
|
5284
6200
|
}
|
|
5285
6201
|
try {
|
|
5286
6202
|
const input = await readHookInput();
|
|
5287
|
-
const client2 = new
|
|
6203
|
+
const client2 = new MindGraph({
|
|
5288
6204
|
baseUrl: hookBaseUrl || "https://api.mindgraph.cloud",
|
|
5289
6205
|
apiKey: hookApiKey,
|
|
5290
6206
|
orgId: process.env.MINDGRAPH_ORG_ID,
|
package/dist/index.js
CHANGED