@productbrain/mcp 0.0.1-beta.12 → 0.0.1-beta.14
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/{chunk-KISCDOJ2.js → chunk-HLXF3QPE.js} +184 -66
- package/dist/chunk-HLXF3QPE.js.map +1 -0
- package/dist/chunk-MV3VHRMV.js +4538 -0
- package/dist/chunk-MV3VHRMV.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/http.js +374 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +10 -4525
- package/dist/index.js.map +1 -1
- package/dist/{setup-XXUPPFF2.js → setup-GZ5OZ5OP.js} +3 -5
- package/dist/{setup-XXUPPFF2.js.map → setup-GZ5OZ5OP.js.map} +1 -1
- package/dist/{smart-capture-SR2ETT67.js → smart-capture-YMTYXB46.js} +2 -2
- package/package.json +4 -1
- package/dist/chunk-KISCDOJ2.js.map +0 -1
- /package/dist/{smart-capture-SR2ETT67.js.map → smart-capture-YMTYXB46.js.map} +0 -0
|
@@ -5,79 +5,149 @@ import {
|
|
|
5
5
|
// src/tools/smart-capture.ts
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
|
+
// src/auth.ts
|
|
9
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
10
|
+
var requestStore = new AsyncLocalStorage();
|
|
11
|
+
function runWithAuth(auth, fn) {
|
|
12
|
+
return requestStore.run(auth, fn);
|
|
13
|
+
}
|
|
14
|
+
function getRequestApiKey() {
|
|
15
|
+
return requestStore.getStore()?.apiKey;
|
|
16
|
+
}
|
|
17
|
+
var SESSION_TTL_MS = 30 * 60 * 1e3;
|
|
18
|
+
var MAX_KEYS = 100;
|
|
19
|
+
var keyStateMap = /* @__PURE__ */ new Map();
|
|
20
|
+
function newKeyState() {
|
|
21
|
+
return {
|
|
22
|
+
workspaceId: null,
|
|
23
|
+
workspaceSlug: null,
|
|
24
|
+
workspaceName: null,
|
|
25
|
+
workspaceCreatedAt: null,
|
|
26
|
+
agentSessionId: null,
|
|
27
|
+
apiKeyId: null,
|
|
28
|
+
apiKeyScope: "readwrite",
|
|
29
|
+
sessionOriented: false,
|
|
30
|
+
sessionClosed: false,
|
|
31
|
+
lastAccess: Date.now()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function getKeyState(apiKey) {
|
|
35
|
+
let s = keyStateMap.get(apiKey);
|
|
36
|
+
if (!s) {
|
|
37
|
+
s = newKeyState();
|
|
38
|
+
keyStateMap.set(apiKey, s);
|
|
39
|
+
evictStale();
|
|
40
|
+
}
|
|
41
|
+
s.lastAccess = Date.now();
|
|
42
|
+
return s;
|
|
43
|
+
}
|
|
44
|
+
function evictStale() {
|
|
45
|
+
if (keyStateMap.size <= MAX_KEYS) return;
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
for (const [key, s] of keyStateMap) {
|
|
48
|
+
if (now - s.lastAccess > SESSION_TTL_MS) keyStateMap.delete(key);
|
|
49
|
+
}
|
|
50
|
+
if (keyStateMap.size > MAX_KEYS) {
|
|
51
|
+
const sorted = [...keyStateMap.entries()].sort((a, b) => a[1].lastAccess - b[1].lastAccess);
|
|
52
|
+
for (let i = 0; i < sorted.length - MAX_KEYS; i++) {
|
|
53
|
+
keyStateMap.delete(sorted[i][0]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
8
58
|
// src/client.ts
|
|
9
59
|
var DEFAULT_CLOUD_URL = "https://trustworthy-kangaroo-277.convex.site";
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
60
|
+
var _stdioState = {
|
|
61
|
+
workspaceId: null,
|
|
62
|
+
workspaceSlug: null,
|
|
63
|
+
workspaceName: null,
|
|
64
|
+
workspaceCreatedAt: null,
|
|
65
|
+
agentSessionId: null,
|
|
66
|
+
apiKeyId: null,
|
|
67
|
+
apiKeyScope: "readwrite",
|
|
68
|
+
sessionOriented: false,
|
|
69
|
+
sessionClosed: false,
|
|
70
|
+
lastAccess: 0
|
|
71
|
+
};
|
|
72
|
+
function state() {
|
|
73
|
+
const reqKey = getRequestApiKey();
|
|
74
|
+
if (reqKey) return getKeyState(reqKey);
|
|
75
|
+
return _stdioState;
|
|
76
|
+
}
|
|
77
|
+
function getActiveApiKey() {
|
|
78
|
+
const fromRequest = getRequestApiKey();
|
|
79
|
+
if (fromRequest) return fromRequest;
|
|
80
|
+
const fromEnv = process.env.PRODUCTBRAIN_API_KEY;
|
|
81
|
+
if (!fromEnv) throw new Error("No API key available \u2014 set PRODUCTBRAIN_API_KEY or provide Bearer token");
|
|
82
|
+
return fromEnv;
|
|
83
|
+
}
|
|
19
84
|
function getAgentSessionId() {
|
|
20
|
-
return
|
|
85
|
+
return state().agentSessionId;
|
|
21
86
|
}
|
|
22
87
|
function isSessionOriented() {
|
|
23
|
-
return sessionOriented;
|
|
88
|
+
return state().sessionOriented;
|
|
24
89
|
}
|
|
25
90
|
function setSessionOriented(value) {
|
|
26
|
-
sessionOriented = value;
|
|
91
|
+
state().sessionOriented = value;
|
|
27
92
|
}
|
|
28
93
|
async function startAgentSession() {
|
|
29
94
|
const workspaceId = await getWorkspaceId();
|
|
30
|
-
|
|
95
|
+
const s = state();
|
|
96
|
+
if (!s.apiKeyId) {
|
|
31
97
|
throw new Error("Cannot start session: API key ID not resolved. Ensure workspace resolution completed.");
|
|
32
98
|
}
|
|
33
99
|
const result = await mcpCall("agent.startSession", {
|
|
34
100
|
workspaceId,
|
|
35
|
-
apiKeyId:
|
|
101
|
+
apiKeyId: s.apiKeyId
|
|
36
102
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
sessionOriented = false;
|
|
40
|
-
sessionClosed = false;
|
|
103
|
+
s.agentSessionId = result.sessionId;
|
|
104
|
+
s.apiKeyScope = result.toolsScope;
|
|
105
|
+
s.sessionOriented = false;
|
|
106
|
+
s.sessionClosed = false;
|
|
41
107
|
return result;
|
|
42
108
|
}
|
|
43
109
|
async function closeAgentSession() {
|
|
44
|
-
|
|
110
|
+
const s = state();
|
|
111
|
+
if (!s.agentSessionId) return;
|
|
45
112
|
try {
|
|
46
113
|
await mcpCall("agent.closeSession", {
|
|
47
|
-
sessionId:
|
|
114
|
+
sessionId: s.agentSessionId,
|
|
48
115
|
status: "closed"
|
|
49
116
|
});
|
|
50
117
|
} finally {
|
|
51
|
-
sessionClosed = true;
|
|
52
|
-
|
|
53
|
-
sessionOriented = false;
|
|
118
|
+
s.sessionClosed = true;
|
|
119
|
+
s.agentSessionId = null;
|
|
120
|
+
s.sessionOriented = false;
|
|
54
121
|
}
|
|
55
122
|
}
|
|
56
123
|
async function orphanAgentSession() {
|
|
57
|
-
|
|
124
|
+
const s = state();
|
|
125
|
+
if (!s.agentSessionId) return;
|
|
58
126
|
try {
|
|
59
127
|
await mcpCall("agent.closeSession", {
|
|
60
|
-
sessionId:
|
|
128
|
+
sessionId: s.agentSessionId,
|
|
61
129
|
status: "orphaned"
|
|
62
130
|
});
|
|
63
131
|
} catch {
|
|
64
132
|
} finally {
|
|
65
|
-
|
|
66
|
-
sessionOriented = false;
|
|
133
|
+
s.agentSessionId = null;
|
|
134
|
+
s.sessionOriented = false;
|
|
67
135
|
}
|
|
68
136
|
}
|
|
69
137
|
function touchSessionActivity() {
|
|
70
|
-
|
|
138
|
+
const s = state();
|
|
139
|
+
if (!s.agentSessionId) return;
|
|
71
140
|
mcpCall("agent.touchSession", {
|
|
72
|
-
sessionId:
|
|
141
|
+
sessionId: s.agentSessionId
|
|
73
142
|
}).catch(() => {
|
|
74
143
|
});
|
|
75
144
|
}
|
|
76
145
|
async function recordSessionActivity(activity) {
|
|
77
|
-
|
|
146
|
+
const s = state();
|
|
147
|
+
if (!s.agentSessionId) return;
|
|
78
148
|
try {
|
|
79
149
|
await mcpCall("agent.recordActivity", {
|
|
80
|
-
sessionId:
|
|
150
|
+
sessionId: s.agentSessionId,
|
|
81
151
|
...activity
|
|
82
152
|
});
|
|
83
153
|
} catch {
|
|
@@ -94,6 +164,9 @@ function bootstrap() {
|
|
|
94
164
|
}
|
|
95
165
|
process.env.CONVEX_SITE_URL ??= process.env.PRODUCTBRAIN_URL ?? DEFAULT_CLOUD_URL;
|
|
96
166
|
}
|
|
167
|
+
function bootstrapHttp() {
|
|
168
|
+
process.env.CONVEX_SITE_URL ??= process.env.PRODUCTBRAIN_URL ?? DEFAULT_CLOUD_URL;
|
|
169
|
+
}
|
|
97
170
|
function getEnv(key) {
|
|
98
171
|
const value = process.env[key];
|
|
99
172
|
if (!value) throw new Error(`${key} environment variable is required`);
|
|
@@ -104,7 +177,7 @@ function shouldLogAudit(status) {
|
|
|
104
177
|
}
|
|
105
178
|
function audit(fn, status, durationMs, errorMsg) {
|
|
106
179
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
107
|
-
const workspace =
|
|
180
|
+
const workspace = state().workspaceId ?? "unresolved";
|
|
108
181
|
const entry = { ts, fn, workspace, status, durationMs };
|
|
109
182
|
if (errorMsg) entry.error = errorMsg;
|
|
110
183
|
auditBuffer.push(entry);
|
|
@@ -125,7 +198,7 @@ function getAuditLog() {
|
|
|
125
198
|
}
|
|
126
199
|
async function mcpCall(fn, args = {}) {
|
|
127
200
|
const siteUrl = getEnv("CONVEX_SITE_URL").replace(/\/$/, "");
|
|
128
|
-
const apiKey =
|
|
201
|
+
const apiKey = getActiveApiKey();
|
|
129
202
|
const start = Date.now();
|
|
130
203
|
let res;
|
|
131
204
|
try {
|
|
@@ -147,19 +220,22 @@ async function mcpCall(fn, args = {}) {
|
|
|
147
220
|
throw new Error(`MCP call "${fn}" failed (${res.status}): ${json.error ?? "unknown error"}`);
|
|
148
221
|
}
|
|
149
222
|
audit(fn, "ok", Date.now() - start);
|
|
150
|
-
|
|
223
|
+
const s = state();
|
|
224
|
+
if (s.agentSessionId && fn !== "agent.touchSession" && fn !== "agent.startSession") {
|
|
151
225
|
touchSessionActivity();
|
|
152
226
|
}
|
|
153
227
|
return json.data;
|
|
154
228
|
}
|
|
155
|
-
var
|
|
229
|
+
var resolveInFlightMap = /* @__PURE__ */ new Map();
|
|
156
230
|
async function getWorkspaceId() {
|
|
157
|
-
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
231
|
+
const s = state();
|
|
232
|
+
if (s.workspaceId) return s.workspaceId;
|
|
233
|
+
const apiKey = getActiveApiKey();
|
|
234
|
+
const existing = resolveInFlightMap.get(apiKey);
|
|
235
|
+
if (existing) return existing;
|
|
236
|
+
const promise = resolveWorkspaceWithRetry().finally(() => resolveInFlightMap.delete(apiKey));
|
|
237
|
+
resolveInFlightMap.set(apiKey, promise);
|
|
238
|
+
return promise;
|
|
163
239
|
}
|
|
164
240
|
async function resolveWorkspaceWithRetry(maxRetries = 2) {
|
|
165
241
|
let lastError = null;
|
|
@@ -171,13 +247,14 @@ async function resolveWorkspaceWithRetry(maxRetries = 2) {
|
|
|
171
247
|
"API key is valid but no workspace is associated. Run `npx productbrain setup` or regenerate your key."
|
|
172
248
|
);
|
|
173
249
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (workspace.
|
|
180
|
-
|
|
250
|
+
const s = state();
|
|
251
|
+
s.workspaceId = workspace._id;
|
|
252
|
+
s.workspaceSlug = workspace.slug;
|
|
253
|
+
s.workspaceName = workspace.name;
|
|
254
|
+
s.workspaceCreatedAt = workspace.createdAt ?? null;
|
|
255
|
+
if (workspace.keyScope) s.apiKeyScope = workspace.keyScope;
|
|
256
|
+
if (workspace.keyId) s.apiKeyId = workspace.keyId;
|
|
257
|
+
return s.workspaceId;
|
|
181
258
|
} catch (err) {
|
|
182
259
|
lastError = err;
|
|
183
260
|
const isTransient = /network error|fetch failed|ECONNREFUSED|ETIMEDOUT/i.test(err.message);
|
|
@@ -194,11 +271,12 @@ async function resolveWorkspaceWithRetry(maxRetries = 2) {
|
|
|
194
271
|
}
|
|
195
272
|
async function getWorkspaceContext() {
|
|
196
273
|
const workspaceId = await getWorkspaceId();
|
|
274
|
+
const s = state();
|
|
197
275
|
return {
|
|
198
276
|
workspaceId,
|
|
199
|
-
workspaceSlug:
|
|
200
|
-
workspaceName:
|
|
201
|
-
createdAt:
|
|
277
|
+
workspaceSlug: s.workspaceSlug ?? "unknown",
|
|
278
|
+
workspaceName: s.workspaceName ?? "unknown",
|
|
279
|
+
createdAt: s.workspaceCreatedAt
|
|
202
280
|
};
|
|
203
281
|
}
|
|
204
282
|
async function mcpQuery(fn, args = {}) {
|
|
@@ -210,36 +288,38 @@ async function mcpMutation(fn, args = {}) {
|
|
|
210
288
|
return mcpCall(fn, { ...args, workspaceId });
|
|
211
289
|
}
|
|
212
290
|
function requireWriteAccess() {
|
|
213
|
-
|
|
291
|
+
const s = state();
|
|
292
|
+
if (!s.agentSessionId) {
|
|
214
293
|
throw new Error(
|
|
215
294
|
"Agent session required for write operations. Call `agent-start` first."
|
|
216
295
|
);
|
|
217
296
|
}
|
|
218
|
-
if (sessionClosed) {
|
|
297
|
+
if (s.sessionClosed) {
|
|
219
298
|
throw new Error(
|
|
220
299
|
"Agent session has been closed. Write tools are no longer available."
|
|
221
300
|
);
|
|
222
301
|
}
|
|
223
|
-
if (!sessionOriented) {
|
|
302
|
+
if (!s.sessionOriented) {
|
|
224
303
|
throw new Error(
|
|
225
304
|
"Orientation required before writing to the Chain. Call 'orient' first."
|
|
226
305
|
);
|
|
227
306
|
}
|
|
228
|
-
if (
|
|
307
|
+
if (s.apiKeyScope === "read") {
|
|
229
308
|
throw new Error(
|
|
230
309
|
"This API key has read-only scope. Write tools are not available."
|
|
231
310
|
);
|
|
232
311
|
}
|
|
233
312
|
}
|
|
234
313
|
async function recoverSessionState() {
|
|
235
|
-
|
|
314
|
+
const s = state();
|
|
315
|
+
if (!s.workspaceId) return;
|
|
236
316
|
try {
|
|
237
|
-
const session = await mcpCall("agent.getActiveSession", { workspaceId:
|
|
317
|
+
const session = await mcpCall("agent.getActiveSession", { workspaceId: s.workspaceId });
|
|
238
318
|
if (session && session.status === "active") {
|
|
239
|
-
|
|
240
|
-
sessionOriented = session.oriented;
|
|
241
|
-
|
|
242
|
-
sessionClosed = false;
|
|
319
|
+
s.agentSessionId = session._id;
|
|
320
|
+
s.sessionOriented = session.oriented;
|
|
321
|
+
s.apiKeyScope = session.toolsScope;
|
|
322
|
+
s.sessionClosed = false;
|
|
243
323
|
}
|
|
244
324
|
} catch {
|
|
245
325
|
}
|
|
@@ -298,6 +378,12 @@ var COMMON_CHECKS = {
|
|
|
298
378
|
return colls.size >= 2;
|
|
299
379
|
},
|
|
300
380
|
suggestion: () => "Try linking to entries in different collections (glossary, business-rules, strategy)."
|
|
381
|
+
},
|
|
382
|
+
hasType: {
|
|
383
|
+
id: "has-type",
|
|
384
|
+
label: "Has canonical type",
|
|
385
|
+
check: (ctx) => !!ctx.data?.canonicalKey || !!ctx.canonicalKey,
|
|
386
|
+
suggestion: () => "Classify this entry with a canonical type for better context assembly. Use update-entry to set canonicalKey."
|
|
301
387
|
}
|
|
302
388
|
};
|
|
303
389
|
var PROFILES = /* @__PURE__ */ new Map([
|
|
@@ -331,6 +417,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
331
417
|
COMMON_CHECKS.clearName,
|
|
332
418
|
COMMON_CHECKS.hasDescription,
|
|
333
419
|
COMMON_CHECKS.hasRelations,
|
|
420
|
+
COMMON_CHECKS.hasType,
|
|
334
421
|
{
|
|
335
422
|
id: "has-severity",
|
|
336
423
|
label: "Severity specified",
|
|
@@ -371,6 +458,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
371
458
|
COMMON_CHECKS.clearName,
|
|
372
459
|
COMMON_CHECKS.hasDescription,
|
|
373
460
|
COMMON_CHECKS.hasRelations,
|
|
461
|
+
COMMON_CHECKS.hasType,
|
|
374
462
|
{
|
|
375
463
|
id: "has-rationale",
|
|
376
464
|
label: "Rationale provided",
|
|
@@ -415,6 +503,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
415
503
|
},
|
|
416
504
|
qualityChecks: [
|
|
417
505
|
COMMON_CHECKS.clearName,
|
|
506
|
+
COMMON_CHECKS.hasType,
|
|
418
507
|
{
|
|
419
508
|
id: "has-canonical",
|
|
420
509
|
label: "Canonical definition provided (>20 chars)",
|
|
@@ -450,6 +539,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
450
539
|
},
|
|
451
540
|
qualityChecks: [
|
|
452
541
|
COMMON_CHECKS.clearName,
|
|
542
|
+
COMMON_CHECKS.hasType,
|
|
453
543
|
{
|
|
454
544
|
id: "has-rationale",
|
|
455
545
|
label: "Rationale provided (>30 chars)",
|
|
@@ -478,6 +568,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
478
568
|
COMMON_CHECKS.clearName,
|
|
479
569
|
COMMON_CHECKS.hasDescription,
|
|
480
570
|
COMMON_CHECKS.hasRelations,
|
|
571
|
+
COMMON_CHECKS.hasType,
|
|
481
572
|
{
|
|
482
573
|
id: "has-owner",
|
|
483
574
|
label: "Owner assigned",
|
|
@@ -502,6 +593,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
502
593
|
COMMON_CHECKS.clearName,
|
|
503
594
|
COMMON_CHECKS.hasDescription,
|
|
504
595
|
COMMON_CHECKS.hasRelations,
|
|
596
|
+
COMMON_CHECKS.hasType,
|
|
505
597
|
{
|
|
506
598
|
id: "has-behaviors",
|
|
507
599
|
label: "Behaviors described",
|
|
@@ -520,6 +612,7 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
520
612
|
COMMON_CHECKS.clearName,
|
|
521
613
|
COMMON_CHECKS.hasDescription,
|
|
522
614
|
COMMON_CHECKS.hasRelations,
|
|
615
|
+
COMMON_CHECKS.hasType,
|
|
523
616
|
COMMON_CHECKS.diverseRelations
|
|
524
617
|
]
|
|
525
618
|
}],
|
|
@@ -554,7 +647,8 @@ var PROFILES = /* @__PURE__ */ new Map([
|
|
|
554
647
|
qualityChecks: [
|
|
555
648
|
COMMON_CHECKS.clearName,
|
|
556
649
|
COMMON_CHECKS.hasDescription,
|
|
557
|
-
COMMON_CHECKS.hasRelations
|
|
650
|
+
COMMON_CHECKS.hasRelations,
|
|
651
|
+
COMMON_CHECKS.hasType
|
|
558
652
|
]
|
|
559
653
|
}],
|
|
560
654
|
["tracking-events", {
|
|
@@ -578,7 +672,8 @@ var FALLBACK_PROFILE = {
|
|
|
578
672
|
qualityChecks: [
|
|
579
673
|
COMMON_CHECKS.clearName,
|
|
580
674
|
COMMON_CHECKS.hasDescription,
|
|
581
|
-
COMMON_CHECKS.hasRelations
|
|
675
|
+
COMMON_CHECKS.hasRelations,
|
|
676
|
+
COMMON_CHECKS.hasType
|
|
582
677
|
]
|
|
583
678
|
};
|
|
584
679
|
function generateEntryId(prefix) {
|
|
@@ -698,6 +793,7 @@ async function checkEntryQuality(entryId) {
|
|
|
698
793
|
description,
|
|
699
794
|
data: entry.data ?? {},
|
|
700
795
|
entryId: entry.entryId ?? "",
|
|
796
|
+
canonicalKey: entry.canonicalKey,
|
|
701
797
|
linksCreated,
|
|
702
798
|
linksSuggested: [],
|
|
703
799
|
collectionFields: []
|
|
@@ -740,11 +836,12 @@ function registerSmartCaptureTools(server) {
|
|
|
740
836
|
name: z.string().describe("Display name \u2014 be specific (e.g. 'Convex adjacency list won't scale for graph traversal')"),
|
|
741
837
|
description: z.string().describe("Full context \u2014 what's happening, why it matters, what you observed"),
|
|
742
838
|
context: z.string().optional().describe("Optional additional context (e.g. 'Observed during gather-context calls taking 700ms+')"),
|
|
743
|
-
entryId: z.string().optional().describe("Optional custom entry ID (e.g. 'TEN-my-id'). Auto-generated if omitted.")
|
|
839
|
+
entryId: z.string().optional().describe("Optional custom entry ID (e.g. 'TEN-my-id'). Auto-generated if omitted."),
|
|
840
|
+
canonicalKey: z.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'vision'). Auto-assigned from collection if omitted.")
|
|
744
841
|
},
|
|
745
842
|
annotations: { destructiveHint: false }
|
|
746
843
|
},
|
|
747
|
-
async ({ collection, name, description, context, entryId }) => {
|
|
844
|
+
async ({ collection, name, description, context, entryId, canonicalKey }) => {
|
|
748
845
|
requireWriteAccess();
|
|
749
846
|
const profile = PROFILES.get(collection) ?? FALLBACK_PROFILE;
|
|
750
847
|
const col = await mcpQuery("chain.getCollection", { slug: collection });
|
|
@@ -815,6 +912,7 @@ Or use \`list-collections\` to see available collections.`
|
|
|
815
912
|
name,
|
|
816
913
|
status,
|
|
817
914
|
data,
|
|
915
|
+
canonicalKey,
|
|
818
916
|
createdBy: agentId ? `agent:${agentId}` : "capture"
|
|
819
917
|
});
|
|
820
918
|
await recordSessionActivity({ entryCreated: finalEntryId || internalId });
|
|
@@ -892,11 +990,25 @@ Use \`get-entry\` to inspect the existing entry, or \`update-entry\` to modify i
|
|
|
892
990
|
context,
|
|
893
991
|
data,
|
|
894
992
|
entryId: finalEntryId,
|
|
993
|
+
canonicalKey,
|
|
895
994
|
linksCreated,
|
|
896
995
|
linksSuggested,
|
|
897
996
|
collectionFields: col.fields ?? []
|
|
898
997
|
};
|
|
899
998
|
const quality = scoreQuality(captureCtx, profile);
|
|
999
|
+
let cardinalityWarning = null;
|
|
1000
|
+
const resolvedCK = canonicalKey ?? captureCtx.canonicalKey;
|
|
1001
|
+
if (resolvedCK) {
|
|
1002
|
+
try {
|
|
1003
|
+
const check = await mcpQuery("chain.checkCardinalityWarning", {
|
|
1004
|
+
canonicalKey: resolvedCK
|
|
1005
|
+
});
|
|
1006
|
+
if (check?.warning) {
|
|
1007
|
+
cardinalityWarning = check.warning;
|
|
1008
|
+
}
|
|
1009
|
+
} catch {
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
900
1012
|
const contradictionWarnings = await runContradictionCheck(name, description);
|
|
901
1013
|
if (contradictionWarnings.length > 0) {
|
|
902
1014
|
await recordSessionActivity({ contradictionWarning: true });
|
|
@@ -930,6 +1042,10 @@ Use \`get-entry\` to inspect the existing entry, or \`update-entry\` to modify i
|
|
|
930
1042
|
lines.push("");
|
|
931
1043
|
lines.push(`_To improve: \`update-entry entryId="${finalEntryId}"\` to fill missing fields._`);
|
|
932
1044
|
}
|
|
1045
|
+
if (cardinalityWarning) {
|
|
1046
|
+
lines.push("");
|
|
1047
|
+
lines.push(`**Cardinality warning:** ${cardinalityWarning}`);
|
|
1048
|
+
}
|
|
933
1049
|
if (contradictionWarnings.length > 0) {
|
|
934
1050
|
lines.push("");
|
|
935
1051
|
lines.push("\u26A0 Contradiction check: proposed entry matched existing governance entries:");
|
|
@@ -1279,6 +1395,7 @@ async function runContradictionCheck(name, description) {
|
|
|
1279
1395
|
}
|
|
1280
1396
|
|
|
1281
1397
|
export {
|
|
1398
|
+
runWithAuth,
|
|
1282
1399
|
getAgentSessionId,
|
|
1283
1400
|
isSessionOriented,
|
|
1284
1401
|
setSessionOriented,
|
|
@@ -1287,6 +1404,7 @@ export {
|
|
|
1287
1404
|
orphanAgentSession,
|
|
1288
1405
|
recordSessionActivity,
|
|
1289
1406
|
bootstrap,
|
|
1407
|
+
bootstrapHttp,
|
|
1290
1408
|
getAuditLog,
|
|
1291
1409
|
mcpCall,
|
|
1292
1410
|
getWorkspaceId,
|
|
@@ -1300,4 +1418,4 @@ export {
|
|
|
1300
1418
|
registerSmartCaptureTools,
|
|
1301
1419
|
runContradictionCheck
|
|
1302
1420
|
};
|
|
1303
|
-
//# sourceMappingURL=chunk-
|
|
1421
|
+
//# sourceMappingURL=chunk-HLXF3QPE.js.map
|