@productbrain/mcp 0.0.1-beta.160 → 0.0.1-beta.162
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.
|
@@ -1838,7 +1838,15 @@ var captureSchema = z2.object({
|
|
|
1838
1838
|
sourceRef: z2.string().optional().describe("URI or path of the source document backing this entry (e.g. 'meeting-2026-03-28.md', 'import://batch-5'). Stored as top-level entry field, not in data."),
|
|
1839
1839
|
sourceExcerpt: z2.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data."),
|
|
1840
1840
|
// WP-316 S3: Preview gate — dry-run mode. Returns what would happen, no DB writes.
|
|
1841
|
-
preview: z2.boolean().optional().describe("If true, validates the capture without writing. Returns what would happen. Default false.")
|
|
1841
|
+
preview: z2.boolean().optional().describe("If true, validates the capture without writing. Returns what would happen. Default false."),
|
|
1842
|
+
// WP-318 S2: Pre-write grounding — run link suggestion before creating entry.
|
|
1843
|
+
suggestOnly: z2.boolean().optional().describe(
|
|
1844
|
+
"If true, runs pre-write grounding (suggestLinksForCapture) and returns a groundingReport WITHOUT creating any entry. Use to preview graph participation before committing. Default false."
|
|
1845
|
+
),
|
|
1846
|
+
// WP-318 S2: Format for groundingReport in response.
|
|
1847
|
+
format: z2.enum(["agent", "human"]).optional().describe(
|
|
1848
|
+
"Response format for grounding data. 'agent' (default): full JSON groundingReport. 'human': compressed summary string appended to the capture summary."
|
|
1849
|
+
)
|
|
1842
1850
|
});
|
|
1843
1851
|
var batchCaptureSchema = z2.object({
|
|
1844
1852
|
entries: z2.array(z2.object({
|
|
@@ -2266,7 +2274,7 @@ function registerSmartCaptureTools(server) {
|
|
|
2266
2274
|
inputSchema: captureSchema.shape,
|
|
2267
2275
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
2268
2276
|
},
|
|
2269
|
-
withEnvelope(async ({ collection, name, description, context, entryId, canonicalKey, data: userData, links, autoCommit, sourceRef, sourceExcerpt, preview }) => {
|
|
2277
|
+
withEnvelope(async ({ collection, name, description, context, entryId, canonicalKey, data: userData, links, autoCommit, sourceRef, sourceExcerpt, preview, suggestOnly, format }) => {
|
|
2270
2278
|
requireWriteAccess();
|
|
2271
2279
|
const timingStart = Date.now();
|
|
2272
2280
|
const wsCtx = await getWorkspaceContext();
|
|
@@ -2341,6 +2349,71 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
2341
2349
|
)
|
|
2342
2350
|
};
|
|
2343
2351
|
}
|
|
2352
|
+
const skipAutoDiscoveryEarly = links && links.length > 0;
|
|
2353
|
+
const groundingStart = Date.now();
|
|
2354
|
+
const groundingPromise = !skipAutoDiscoveryEarly && (name || description) ? mcpQuery("chain.suggestLinksForCapture", {
|
|
2355
|
+
entries: [{ name, description: description ?? "", collectionHint: resolvedCollection }],
|
|
2356
|
+
limit: 5,
|
|
2357
|
+
threshold: 2
|
|
2358
|
+
}).catch(() => null) : Promise.resolve(null);
|
|
2359
|
+
const groundingRaw = await groundingPromise;
|
|
2360
|
+
const groundingElapsedMs = Date.now() - groundingStart;
|
|
2361
|
+
const groundingEntry = groundingRaw?.[0] ?? null;
|
|
2362
|
+
const groundingRelated = groundingEntry?.related ?? [];
|
|
2363
|
+
const groundingDuplicates = groundingEntry?.duplicates ?? [];
|
|
2364
|
+
const groundingGovernance = (groundingEntry?.governance ?? []).map((g) => ({
|
|
2365
|
+
entryId: g.entryId,
|
|
2366
|
+
name: g.name,
|
|
2367
|
+
collectionSlug: g.collectionSlug
|
|
2368
|
+
}));
|
|
2369
|
+
const groundingReport = {
|
|
2370
|
+
related: groundingRelated.map((r) => ({
|
|
2371
|
+
entryId: r.entryId,
|
|
2372
|
+
name: r.name,
|
|
2373
|
+
collectionSlug: r.collectionSlug,
|
|
2374
|
+
overlapRatio: r.overlapRatio,
|
|
2375
|
+
recommendedRelationType: r.recommendedRelationType,
|
|
2376
|
+
reasoning: r.reasoning
|
|
2377
|
+
})),
|
|
2378
|
+
duplicates: groundingDuplicates.map((d) => ({
|
|
2379
|
+
entryId: d.entryId,
|
|
2380
|
+
name: d.name,
|
|
2381
|
+
collectionSlug: d.collectionSlug,
|
|
2382
|
+
matchType: d.matchType,
|
|
2383
|
+
overlapRatio: d.overlapRatio
|
|
2384
|
+
})),
|
|
2385
|
+
governance: groundingGovernance
|
|
2386
|
+
};
|
|
2387
|
+
if (suggestOnly) {
|
|
2388
|
+
const hasSuggestions = groundingReport.related.length > 0 || groundingReport.duplicates.length > 0;
|
|
2389
|
+
const summaryText = hasSuggestions ? `Grounding preview for "${name}": ${groundingReport.related.length} related, ${groundingReport.duplicates.length} possible duplicates. No entry created.` : `Grounding preview for "${name}": no similar entries found. Safe to capture.`;
|
|
2390
|
+
return {
|
|
2391
|
+
content: [{
|
|
2392
|
+
type: "text",
|
|
2393
|
+
text: `# Grounding Preview \u2014 No Entry Created
|
|
2394
|
+
|
|
2395
|
+
${summaryText}
|
|
2396
|
+
|
|
2397
|
+
` + (groundingReport.related.length > 0 ? `## Related entries
|
|
2398
|
+
${groundingReport.related.map((r) => `- **${r.entryId}** ${r.name} [${r.collectionSlug}] \u2014 ${r.reasoning}`).join("\n")}
|
|
2399
|
+
|
|
2400
|
+
` : "") + (groundingReport.duplicates.length > 0 ? `## Possible duplicates
|
|
2401
|
+
${groundingReport.duplicates.map((d) => `- **${d.entryId}** ${d.name} [${d.collectionSlug}] (${d.matchType}, overlap: ${d.overlapRatio})`).join("\n")}
|
|
2402
|
+
|
|
2403
|
+
` : "") + (groundingReport.governance.length > 0 ? `## Governance entries to review
|
|
2404
|
+
${groundingReport.governance.map((g) => `- **${g.entryId}** ${g.name} [${g.collectionSlug}]`).join("\n")}
|
|
2405
|
+
|
|
2406
|
+
` : "") + `_Call \`capture\` without \`suggestOnly\` to proceed with entry creation._`
|
|
2407
|
+
}],
|
|
2408
|
+
structuredContent: {
|
|
2409
|
+
...success(
|
|
2410
|
+
summaryText,
|
|
2411
|
+
{ groundingReport, outcome: "suggest_only" },
|
|
2412
|
+
[{ tool: "capture", description: "Capture for real", parameters: { collection: resolvedCollection, name, description } }]
|
|
2413
|
+
)
|
|
2414
|
+
}
|
|
2415
|
+
};
|
|
2416
|
+
}
|
|
2344
2417
|
const data = buildDataFromFields(col.fields ?? [], profile.descriptionField, description);
|
|
2345
2418
|
for (const def of profile.defaults) {
|
|
2346
2419
|
if (def.value !== "infer" && def.value !== "today") {
|
|
@@ -2429,6 +2502,14 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
2429
2502
|
...preview ? { preview: true } : {}
|
|
2430
2503
|
});
|
|
2431
2504
|
if (result?.preview) {
|
|
2505
|
+
const hasGrounding = groundingReport.related.length > 0 || groundingReport.duplicates.length > 0 || groundingReport.governance.length > 0;
|
|
2506
|
+
const groundingSummary = hasGrounding ? `
|
|
2507
|
+
|
|
2508
|
+
**Grounding:** ${[
|
|
2509
|
+
groundingReport.duplicates.length > 0 && `${groundingReport.duplicates.length} possible duplicate${groundingReport.duplicates.length > 1 ? "s" : ""}`,
|
|
2510
|
+
groundingReport.related.length > 0 && `${groundingReport.related.length} related entr${groundingReport.related.length > 1 ? "ies" : "y"}`,
|
|
2511
|
+
groundingReport.governance.length > 0 && `${groundingReport.governance[0]?.entryId} may govern this`
|
|
2512
|
+
].filter(Boolean).join(", ")}.` : "";
|
|
2432
2513
|
const previewEnvelope = success(
|
|
2433
2514
|
`Preview: would capture "${name}" \u2014 no DB writes`,
|
|
2434
2515
|
{
|
|
@@ -2436,7 +2517,8 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
2436
2517
|
name,
|
|
2437
2518
|
collection: resolvedCollection,
|
|
2438
2519
|
outcome: "preview",
|
|
2439
|
-
warnings: result.warnings ?? []
|
|
2520
|
+
warnings: result.warnings ?? [],
|
|
2521
|
+
groundingReport
|
|
2440
2522
|
},
|
|
2441
2523
|
[{ tool: "capture", description: "Capture for real", parameters: { collection: resolvedCollection, name, description } }]
|
|
2442
2524
|
);
|
|
@@ -2448,7 +2530,7 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
2448
2530
|
|
|
2449
2531
|
No DB writes \u2014 call without \`preview:true\` to capture for real.${result.warnings?.length ? `
|
|
2450
2532
|
|
|
2451
|
-
**Warnings:** ${result.warnings.join("; ")}` : ""}` }],
|
|
2533
|
+
**Warnings:** ${result.warnings.join("; ")}` : ""}${groundingSummary}` }],
|
|
2452
2534
|
structuredContent: previewEnvelope
|
|
2453
2535
|
};
|
|
2454
2536
|
}
|
|
@@ -2485,6 +2567,17 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2485
2567
|
throw error;
|
|
2486
2568
|
}
|
|
2487
2569
|
const tAfterCreate = Date.now();
|
|
2570
|
+
void mcpMutation("chain.recordGroundingOutcome", {
|
|
2571
|
+
surface: "mcp",
|
|
2572
|
+
promptShown: groundingReport.governance.length > 0,
|
|
2573
|
+
highestRatio: Math.max(
|
|
2574
|
+
...groundingReport.duplicates.map((d) => d.overlapRatio),
|
|
2575
|
+
...groundingReport.related.map((r) => r.overlapRatio),
|
|
2576
|
+
0
|
|
2577
|
+
),
|
|
2578
|
+
hadGovernance: groundingReport.governance.length > 0,
|
|
2579
|
+
grounding_ms: groundingElapsedMs
|
|
2580
|
+
}).catch(() => void 0);
|
|
2488
2581
|
const linksCreated = [];
|
|
2489
2582
|
const linksSuggested = [];
|
|
2490
2583
|
const userLinkResults = [];
|
|
@@ -2770,6 +2863,19 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2770
2863
|
lines.push(`${i + 1}. **${s.entryId ?? "(no ID)"}**: ${s.name} [${s.collection}]${preview2}`);
|
|
2771
2864
|
}
|
|
2772
2865
|
}
|
|
2866
|
+
if (format === "human") {
|
|
2867
|
+
const hasDuplicates = groundingReport.duplicates.length > 0;
|
|
2868
|
+
const hasRelated = groundingReport.related.length > 0;
|
|
2869
|
+
const hasGov = groundingReport.governance.length > 0;
|
|
2870
|
+
if (hasDuplicates || hasRelated || hasGov) {
|
|
2871
|
+
lines.push("");
|
|
2872
|
+
const parts = [];
|
|
2873
|
+
if (hasDuplicates) parts.push(`${groundingReport.duplicates.length} possible duplicate${groundingReport.duplicates.length > 1 ? "s" : ""}`);
|
|
2874
|
+
if (hasRelated) parts.push(`${groundingReport.related.length} related entr${groundingReport.related.length > 1 ? "ies" : "y"}`);
|
|
2875
|
+
if (hasGov) parts.push(`${groundingReport.governance[0]?.entryId} may govern this`);
|
|
2876
|
+
lines.push(`_Grounding: ${parts.join(", ")}. Review and link if relevant._`);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2773
2879
|
lines.push("");
|
|
2774
2880
|
lines.push(formatQualityReport(quality));
|
|
2775
2881
|
const failedChecks = quality.checks.filter((c) => !c.passed);
|
|
@@ -2946,7 +3052,9 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2946
3052
|
// BET-272 S3: Advisory quality hints — always included (empty array when all criteria pass)
|
|
2947
3053
|
qualityHints: formativeHints,
|
|
2948
3054
|
// BET-272 S5: Advisory relation suggestions from graph (BR-144, STD-147)
|
|
2949
|
-
relationSuggestions: relationSuggestionsFromCreate
|
|
3055
|
+
relationSuggestions: relationSuggestionsFromCreate,
|
|
3056
|
+
// WP-318 S2: Pre-write grounding report — always included (empty arrays when no suggestions)
|
|
3057
|
+
groundingReport
|
|
2950
3058
|
},
|
|
2951
3059
|
next
|
|
2952
3060
|
),
|
|
@@ -11114,7 +11222,16 @@ async function tryMarkOriented(agentSessionId, coherenceSnapshot) {
|
|
|
11114
11222
|
setSessionOriented(true);
|
|
11115
11223
|
return { oriented: true, orientationStatus: "complete" };
|
|
11116
11224
|
} catch {
|
|
11117
|
-
|
|
11225
|
+
if (!coherenceSnapshot) {
|
|
11226
|
+
return { oriented: false, orientationStatus: "failed" };
|
|
11227
|
+
}
|
|
11228
|
+
try {
|
|
11229
|
+
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
11230
|
+
setSessionOriented(true);
|
|
11231
|
+
return { oriented: true, orientationStatus: "complete" };
|
|
11232
|
+
} catch {
|
|
11233
|
+
return { oriented: false, orientationStatus: "failed" };
|
|
11234
|
+
}
|
|
11118
11235
|
}
|
|
11119
11236
|
}
|
|
11120
11237
|
var startSchema = z17.object({
|
|
@@ -13361,6 +13478,25 @@ function formatScanReport(result) {
|
|
|
13361
13478
|
// src/tools/orient.ts
|
|
13362
13479
|
import { z as z22 } from "zod";
|
|
13363
13480
|
var PURPOSE_GAP_PREFIX = "purpose-gap-";
|
|
13481
|
+
async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot) {
|
|
13482
|
+
try {
|
|
13483
|
+
await mcpCall("agent.markOriented", {
|
|
13484
|
+
sessionId: agentSessionId,
|
|
13485
|
+
...coherenceSnapshot ? { coherenceSnapshot } : {}
|
|
13486
|
+
});
|
|
13487
|
+
setSessionOriented(true);
|
|
13488
|
+
return true;
|
|
13489
|
+
} catch {
|
|
13490
|
+
if (!coherenceSnapshot) return false;
|
|
13491
|
+
try {
|
|
13492
|
+
await mcpCall("agent.markOriented", { sessionId: agentSessionId });
|
|
13493
|
+
setSessionOriented(true);
|
|
13494
|
+
return true;
|
|
13495
|
+
} catch {
|
|
13496
|
+
return false;
|
|
13497
|
+
}
|
|
13498
|
+
}
|
|
13499
|
+
}
|
|
13364
13500
|
function extractSessionEntryIds(priorSessions) {
|
|
13365
13501
|
const allSeen = /* @__PURE__ */ new Set();
|
|
13366
13502
|
const all = [];
|
|
@@ -13648,16 +13784,12 @@ function registerOrientTool(server) {
|
|
|
13648
13784
|
}
|
|
13649
13785
|
let orientationStatus2 = "no_session";
|
|
13650
13786
|
if (agentSessionId && hasTaskGrounding) {
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
sessionId: agentSessionId,
|
|
13654
|
-
...coherenceSnapshot ? { coherenceSnapshot } : {}
|
|
13655
|
-
});
|
|
13656
|
-
setSessionOriented(true);
|
|
13787
|
+
const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot);
|
|
13788
|
+
if (orientedOk) {
|
|
13657
13789
|
orientationStatus2 = "complete";
|
|
13658
13790
|
lines.push("---");
|
|
13659
13791
|
lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
|
|
13660
|
-
}
|
|
13792
|
+
} else {
|
|
13661
13793
|
orientationStatus2 = "failed";
|
|
13662
13794
|
lines.push("---");
|
|
13663
13795
|
lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
|
|
@@ -14019,16 +14151,12 @@ function registerOrientTool(server) {
|
|
|
14019
14151
|
}
|
|
14020
14152
|
let orientationStatus = "no_session";
|
|
14021
14153
|
if (agentSessionId && hasTaskGrounding) {
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
sessionId: agentSessionId,
|
|
14025
|
-
...fullCoherenceSnapshot ? { coherenceSnapshot: fullCoherenceSnapshot } : {}
|
|
14026
|
-
});
|
|
14027
|
-
setSessionOriented(true);
|
|
14154
|
+
const orientedOk = await markOrientedWithSnapshotFallback(agentSessionId, fullCoherenceSnapshot);
|
|
14155
|
+
if (orientedOk) {
|
|
14028
14156
|
orientationStatus = "complete";
|
|
14029
14157
|
lines.push("---");
|
|
14030
14158
|
lines.push(`Orientation complete. Session ${agentSessionId}. Write tools available.`);
|
|
14031
|
-
}
|
|
14159
|
+
} else {
|
|
14032
14160
|
orientationStatus = "failed";
|
|
14033
14161
|
lines.push("---");
|
|
14034
14162
|
lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
|
|
@@ -15629,7 +15757,6 @@ export {
|
|
|
15629
15757
|
hashKey,
|
|
15630
15758
|
runWithAuth,
|
|
15631
15759
|
getAgentSessionId,
|
|
15632
|
-
startAgentSession,
|
|
15633
15760
|
orphanAgentSession,
|
|
15634
15761
|
bootstrap,
|
|
15635
15762
|
bootstrapHttp,
|
|
@@ -15639,4 +15766,4 @@ export {
|
|
|
15639
15766
|
SERVER_VERSION,
|
|
15640
15767
|
createProductBrainServer
|
|
15641
15768
|
};
|
|
15642
|
-
//# sourceMappingURL=chunk-
|
|
15769
|
+
//# sourceMappingURL=chunk-EPAHRXLQ.js.map
|