@productbrain/mcp 0.0.1-beta.168 → 0.0.1-beta.171
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.
|
@@ -86,7 +86,7 @@ function getToolContext() {
|
|
|
86
86
|
return toolContextStore.getStore() ?? null;
|
|
87
87
|
}
|
|
88
88
|
var DEFAULT_CLOUD_URL = "https://gateway.productbrain.io";
|
|
89
|
-
var
|
|
89
|
+
var KernelCallError = class extends Error {
|
|
90
90
|
status;
|
|
91
91
|
code;
|
|
92
92
|
/** WP-316 S1a: Structured commit validation — required field keys missing from entry.data. */
|
|
@@ -95,7 +95,7 @@ var McpCallError = class extends Error {
|
|
|
95
95
|
fieldErrors;
|
|
96
96
|
constructor(message, status, code, missingRequiredFields, fieldErrors) {
|
|
97
97
|
super(message);
|
|
98
|
-
this.name = "
|
|
98
|
+
this.name = "KernelCallError";
|
|
99
99
|
this.status = status;
|
|
100
100
|
this.code = code;
|
|
101
101
|
this.missingRequiredFields = missingRequiredFields;
|
|
@@ -184,7 +184,7 @@ async function startAgentSession() {
|
|
|
184
184
|
if (!s.apiKeyId) {
|
|
185
185
|
throw new Error("Cannot start session: API key ID not resolved. Ensure workspace resolution completed.");
|
|
186
186
|
}
|
|
187
|
-
const result = await
|
|
187
|
+
const result = await kernelCall("agent.startSession", {
|
|
188
188
|
workspaceId,
|
|
189
189
|
apiKeyId: s.apiKeyId,
|
|
190
190
|
clientKind: "mcp"
|
|
@@ -204,7 +204,7 @@ async function closeAgentSession() {
|
|
|
204
204
|
if (!s.agentSessionId) return;
|
|
205
205
|
const sessionId = s.agentSessionId;
|
|
206
206
|
try {
|
|
207
|
-
await
|
|
207
|
+
await kernelCall("agent.closeSession", {
|
|
208
208
|
sessionId,
|
|
209
209
|
status: "closed"
|
|
210
210
|
});
|
|
@@ -220,7 +220,7 @@ async function orphanAgentSession() {
|
|
|
220
220
|
if (!s.agentSessionId) return;
|
|
221
221
|
const sessionId = s.agentSessionId;
|
|
222
222
|
try {
|
|
223
|
-
await
|
|
223
|
+
await kernelCall("agent.closeSession", {
|
|
224
224
|
sessionId,
|
|
225
225
|
status: "orphaned"
|
|
226
226
|
});
|
|
@@ -241,7 +241,7 @@ function touchSessionActivity() {
|
|
|
241
241
|
const lastTouchAt = _lastTouchAtBySession.get(sessionId) ?? 0;
|
|
242
242
|
if (now - lastTouchAt < TOUCH_THROTTLE_MS) return;
|
|
243
243
|
_lastTouchAtBySession.set(sessionId, now);
|
|
244
|
-
|
|
244
|
+
kernelCall("agent.touchSession", {
|
|
245
245
|
sessionId
|
|
246
246
|
}).catch(() => {
|
|
247
247
|
});
|
|
@@ -257,7 +257,7 @@ async function recordSessionActivity(activity) {
|
|
|
257
257
|
const s = state();
|
|
258
258
|
if (!s.agentSessionId) return;
|
|
259
259
|
try {
|
|
260
|
-
await
|
|
260
|
+
await kernelCall("agent.recordActivity", {
|
|
261
261
|
sessionId: s.agentSessionId,
|
|
262
262
|
...activity
|
|
263
263
|
});
|
|
@@ -341,7 +341,7 @@ async function callGateway(fn, args) {
|
|
|
341
341
|
const errJson = json;
|
|
342
342
|
const msg = errJson.error ?? errJson.message ?? "unknown error";
|
|
343
343
|
audit(fn, "error", Date.now() - start, errJson.code ? `${msg} [${errJson.code}]` : msg);
|
|
344
|
-
throw new
|
|
344
|
+
throw new KernelCallError(
|
|
345
345
|
`MCP call "${fn}" failed (${res.status}): ${msg}`,
|
|
346
346
|
res.status,
|
|
347
347
|
errJson.code,
|
|
@@ -358,7 +358,7 @@ async function callGateway(fn, args) {
|
|
|
358
358
|
_meta
|
|
359
359
|
};
|
|
360
360
|
}
|
|
361
|
-
async function
|
|
361
|
+
async function kernelCall(fn, args = {}) {
|
|
362
362
|
const cached = getCached(fn, args);
|
|
363
363
|
if (cached !== void 0) {
|
|
364
364
|
return cached;
|
|
@@ -375,7 +375,7 @@ async function mcpCall(fn, args = {}) {
|
|
|
375
375
|
}
|
|
376
376
|
return data;
|
|
377
377
|
}
|
|
378
|
-
async function
|
|
378
|
+
async function kernelCallEnvelope(fn, args = {}) {
|
|
379
379
|
const { data, summary, next, _meta } = await callGateway(fn, args);
|
|
380
380
|
const s = state();
|
|
381
381
|
if (s.agentSessionId && !TOUCH_EXCLUDED.has(fn)) {
|
|
@@ -398,7 +398,7 @@ async function resolveWorkspaceWithRetry(maxRetries = 2) {
|
|
|
398
398
|
let lastError = null;
|
|
399
399
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
400
400
|
try {
|
|
401
|
-
const workspace = await
|
|
401
|
+
const workspace = await kernelCall("resolveWorkspace", {});
|
|
402
402
|
if (!workspace) {
|
|
403
403
|
throw new Error(
|
|
404
404
|
`API key is valid but no workspace is associated. Run \`npx ${MCP_NPX_PACKAGE} setup\` or regenerate your key.`
|
|
@@ -438,13 +438,13 @@ async function getWorkspaceContext() {
|
|
|
438
438
|
governanceMode: s.workspaceGovernanceMode ?? "open"
|
|
439
439
|
};
|
|
440
440
|
}
|
|
441
|
-
async function
|
|
441
|
+
async function kernelQuery(fn, args = {}) {
|
|
442
442
|
const workspaceId = await getWorkspaceId();
|
|
443
|
-
return
|
|
443
|
+
return kernelCall(fn, { ...args, workspaceId });
|
|
444
444
|
}
|
|
445
|
-
async function
|
|
445
|
+
async function kernelMutation(fn, args = {}) {
|
|
446
446
|
const workspaceId = await getWorkspaceId();
|
|
447
|
-
return
|
|
447
|
+
return kernelCall(fn, { ...args, workspaceId });
|
|
448
448
|
}
|
|
449
449
|
function requireActiveSession() {
|
|
450
450
|
const s = state();
|
|
@@ -491,7 +491,7 @@ async function recoverSessionState() {
|
|
|
491
491
|
const s = state();
|
|
492
492
|
if (!s.workspaceId) return;
|
|
493
493
|
try {
|
|
494
|
-
const session = await
|
|
494
|
+
const session = await kernelCall("agent.getActiveSession", { workspaceId: s.workspaceId });
|
|
495
495
|
if (session && session.status === "active") {
|
|
496
496
|
s.agentSessionId = session._id;
|
|
497
497
|
s.sessionOriented = session.oriented;
|
|
@@ -724,7 +724,7 @@ function recordGap(gap) {
|
|
|
724
724
|
}
|
|
725
725
|
function persistGap(gap) {
|
|
726
726
|
const sessionId = getAgentSessionId();
|
|
727
|
-
|
|
727
|
+
kernelMutation("gaps.record", {
|
|
728
728
|
sessionId: sessionId ?? void 0,
|
|
729
729
|
query: gap.query,
|
|
730
730
|
tool: gap.tool,
|
|
@@ -756,7 +756,7 @@ function clearSessionGaps() {
|
|
|
756
756
|
sessionGaps.delete(sessionKey);
|
|
757
757
|
}
|
|
758
758
|
function resolveGapsForEntry(entryName, entryId) {
|
|
759
|
-
|
|
759
|
+
kernelMutation("gaps.resolve", { entryName, entryId }).catch(() => {
|
|
760
760
|
});
|
|
761
761
|
}
|
|
762
762
|
|
|
@@ -764,7 +764,7 @@ function resolveGapsForEntry(entryName, entryId) {
|
|
|
764
764
|
async function resolveCollection(params) {
|
|
765
765
|
const { name, description, typeHint, allowReviewRouting } = params;
|
|
766
766
|
const sessionId = getAgentSessionId();
|
|
767
|
-
const result = await
|
|
767
|
+
const result = await kernelCall("chain.resolveCollection", {
|
|
768
768
|
entryName: name,
|
|
769
769
|
entryDescription: description,
|
|
770
770
|
...typeHint ? { typeHint } : {},
|
|
@@ -779,7 +779,7 @@ import { z } from "zod";
|
|
|
779
779
|
|
|
780
780
|
// src/errors.ts
|
|
781
781
|
var MCP_CALL_ERROR_RE = /^MCP call "[^"]+" failed \(\d+\): (.+)$/s;
|
|
782
|
-
function
|
|
782
|
+
function asKernelCallError(err) {
|
|
783
783
|
if (err instanceof Error && typeof err.code === "string") {
|
|
784
784
|
const code = err.code;
|
|
785
785
|
const match = MCP_CALL_ERROR_RE.exec(err.message);
|
|
@@ -855,7 +855,7 @@ function classifyError(err) {
|
|
|
855
855
|
if (err instanceof ValidationError) {
|
|
856
856
|
return { code: "VALIDATION_ERROR", message };
|
|
857
857
|
}
|
|
858
|
-
const mcpErr =
|
|
858
|
+
const mcpErr = asKernelCallError(err);
|
|
859
859
|
if (mcpErr) {
|
|
860
860
|
const { code: convexCode, cleanMessage, missingRequiredFields, fieldErrors } = mcpErr;
|
|
861
861
|
if (convexCode === "VALIDATION_FAILED") {
|
|
@@ -1073,12 +1073,43 @@ function formatFieldGuidance(fields) {
|
|
|
1073
1073
|
return lines.join("\n");
|
|
1074
1074
|
}
|
|
1075
1075
|
|
|
1076
|
+
// src/lib/inferSourceDate.ts
|
|
1077
|
+
function inferSourceDate(...values) {
|
|
1078
|
+
const combined = values.filter((value) => typeof value === "string" && value.trim().length > 0).join("\n");
|
|
1079
|
+
if (!combined) return void 0;
|
|
1080
|
+
const isoMatch = combined.match(/\b(20\d{2}-\d{2}-\d{2})\b/);
|
|
1081
|
+
if (isoMatch) return isoMatch[1];
|
|
1082
|
+
const monthMatch = combined.match(
|
|
1083
|
+
/\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+(\d{1,2})(?:st|nd|rd|th)?(?:,?\s+(20\d{2}))?\b/i
|
|
1084
|
+
);
|
|
1085
|
+
if (!monthMatch) return void 0;
|
|
1086
|
+
const monthIndex = [
|
|
1087
|
+
"january",
|
|
1088
|
+
"february",
|
|
1089
|
+
"march",
|
|
1090
|
+
"april",
|
|
1091
|
+
"may",
|
|
1092
|
+
"june",
|
|
1093
|
+
"july",
|
|
1094
|
+
"august",
|
|
1095
|
+
"september",
|
|
1096
|
+
"october",
|
|
1097
|
+
"november",
|
|
1098
|
+
"december"
|
|
1099
|
+
].indexOf(monthMatch[1].toLowerCase());
|
|
1100
|
+
if (monthIndex < 0) return void 0;
|
|
1101
|
+
const inferredYear = monthMatch[3] ?? combined.match(/\b(20\d{2})\b/)?.[1] ?? String((/* @__PURE__ */ new Date()).getUTCFullYear());
|
|
1102
|
+
const month = String(monthIndex + 1).padStart(2, "0");
|
|
1103
|
+
const day = monthMatch[2].padStart(2, "0");
|
|
1104
|
+
return `${inferredYear}-${month}-${day}`;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1076
1107
|
// src/lib/collectionCache.ts
|
|
1077
1108
|
var cachedCollections = null;
|
|
1078
1109
|
var cachedBySlug = null;
|
|
1079
1110
|
async function getCollections() {
|
|
1080
1111
|
if (cachedCollections !== null) return cachedCollections;
|
|
1081
|
-
const result = await
|
|
1112
|
+
const result = await kernelQuery("chain.listCollections");
|
|
1082
1113
|
cachedCollections = result ?? [];
|
|
1083
1114
|
cachedBySlug = new Map(cachedCollections.map((c) => [c.slug, c]));
|
|
1084
1115
|
return cachedCollections;
|
|
@@ -1137,35 +1168,6 @@ function inferFieldOption(text, collectionFields, fieldKeys) {
|
|
|
1137
1168
|
}
|
|
1138
1169
|
return bestOption;
|
|
1139
1170
|
}
|
|
1140
|
-
function inferSourceDate(...values) {
|
|
1141
|
-
const combined = values.filter((value) => typeof value === "string" && value.trim().length > 0).join("\n");
|
|
1142
|
-
if (!combined) return void 0;
|
|
1143
|
-
const isoMatch = combined.match(/\b(20\d{2}-\d{2}-\d{2})\b/);
|
|
1144
|
-
if (isoMatch) return isoMatch[1];
|
|
1145
|
-
const monthMatch = combined.match(
|
|
1146
|
-
/\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+(\d{1,2})(?:st|nd|rd|th)?(?:,?\s+(20\d{2}))?\b/i
|
|
1147
|
-
);
|
|
1148
|
-
if (!monthMatch) return void 0;
|
|
1149
|
-
const monthIndex = [
|
|
1150
|
-
"january",
|
|
1151
|
-
"february",
|
|
1152
|
-
"march",
|
|
1153
|
-
"april",
|
|
1154
|
-
"may",
|
|
1155
|
-
"june",
|
|
1156
|
-
"july",
|
|
1157
|
-
"august",
|
|
1158
|
-
"september",
|
|
1159
|
-
"october",
|
|
1160
|
-
"november",
|
|
1161
|
-
"december"
|
|
1162
|
-
].indexOf(monthMatch[1].toLowerCase());
|
|
1163
|
-
if (monthIndex < 0) return void 0;
|
|
1164
|
-
const inferredYear = monthMatch[3] ?? combined.match(/\b(20\d{2})\b/)?.[1] ?? String((/* @__PURE__ */ new Date()).getUTCFullYear());
|
|
1165
|
-
const month = String(monthIndex + 1).padStart(2, "0");
|
|
1166
|
-
const day = monthMatch[2].padStart(2, "0");
|
|
1167
|
-
return `${inferredYear}-${month}-${day}`;
|
|
1168
|
-
}
|
|
1169
1171
|
var COMMON_CHECKS = {
|
|
1170
1172
|
clearName: {
|
|
1171
1173
|
id: "clear-name",
|
|
@@ -1778,7 +1780,7 @@ function formatQualityReport(result) {
|
|
|
1778
1780
|
return lines.join("\n");
|
|
1779
1781
|
}
|
|
1780
1782
|
async function checkEntryQuality(entryId) {
|
|
1781
|
-
const entry = await
|
|
1783
|
+
const entry = await kernelQuery("chain.getEntry", { entryId });
|
|
1782
1784
|
if (!entry) {
|
|
1783
1785
|
return {
|
|
1784
1786
|
text: `Entry \`${entryId}\` not found. Try search to find the right ID.`,
|
|
@@ -1790,7 +1792,7 @@ async function checkEntryQuality(entryId) {
|
|
|
1790
1792
|
for (const c of collections) collMap.set(c._id, c.slug);
|
|
1791
1793
|
const collectionSlug = collMap.get(entry.collectionId) ?? "unknown";
|
|
1792
1794
|
const profile = await getProfile(collectionSlug);
|
|
1793
|
-
const relations = await
|
|
1795
|
+
const relations = await kernelQuery("chain.listEntryRelations", { entryId });
|
|
1794
1796
|
const linksCreated = [];
|
|
1795
1797
|
for (const r of relations) {
|
|
1796
1798
|
const otherId = r.fromId === entry._id ? r.toId : r.fromId;
|
|
@@ -2341,7 +2343,7 @@ function registerSmartCaptureTools(server) {
|
|
|
2341
2343
|
};
|
|
2342
2344
|
}
|
|
2343
2345
|
const profile = await getProfile(resolvedCollection);
|
|
2344
|
-
const col = await
|
|
2346
|
+
const col = await kernelQuery("chain.getCollection", { slug: resolvedCollection });
|
|
2345
2347
|
if (!col) {
|
|
2346
2348
|
const displayName = resolvedCollection.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
2347
2349
|
return {
|
|
@@ -2369,7 +2371,7 @@ Or use \`collections action=list\` to see available collections.`
|
|
|
2369
2371
|
}
|
|
2370
2372
|
const skipAutoDiscoveryEarly = links && links.length > 0;
|
|
2371
2373
|
const groundingStart = Date.now();
|
|
2372
|
-
const groundingPromise = !skipAutoDiscoveryEarly && (name || description) ?
|
|
2374
|
+
const groundingPromise = !skipAutoDiscoveryEarly && (name || description) ? kernelQuery("chain.suggestLinksForCapture", {
|
|
2373
2375
|
entries: [{ name, description: description ?? "", collectionHint: resolvedCollection }],
|
|
2374
2376
|
limit: 5,
|
|
2375
2377
|
threshold: 2
|
|
@@ -2478,7 +2480,7 @@ ${groundingReport.governance.map((g) => `- **${g.entryId}** ${g.name} [${g.colle
|
|
|
2478
2480
|
const shouldDecompose = (isStrategyCapture || isBetCapture) && description.trim().length > 0;
|
|
2479
2481
|
if (shouldDecompose) {
|
|
2480
2482
|
try {
|
|
2481
|
-
const decomposed = await
|
|
2483
|
+
const decomposed = await kernelCall(
|
|
2482
2484
|
"chain.decomposeContent",
|
|
2483
2485
|
{
|
|
2484
2486
|
collectionSlug: resolvedCollection,
|
|
@@ -2509,7 +2511,7 @@ ${groundingReport.governance.map((g) => `- **${g.entryId}** ${g.name} [${g.colle
|
|
|
2509
2511
|
let formativeHints = [];
|
|
2510
2512
|
let relationSuggestionsFromCreate = [];
|
|
2511
2513
|
try {
|
|
2512
|
-
const result = await
|
|
2514
|
+
const result = await kernelMutation("chain.createEntry", {
|
|
2513
2515
|
collectionSlug: resolvedCollection,
|
|
2514
2516
|
entryId: entryId ?? void 0,
|
|
2515
2517
|
name,
|
|
@@ -2588,7 +2590,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2588
2590
|
throw error;
|
|
2589
2591
|
}
|
|
2590
2592
|
const tAfterCreate = Date.now();
|
|
2591
|
-
void
|
|
2593
|
+
void kernelMutation("chain.recordGroundingOutcome", {
|
|
2592
2594
|
surface: "mcp",
|
|
2593
2595
|
promptShown: groundingReport.governance.length > 0,
|
|
2594
2596
|
highestRatio: Math.max(
|
|
@@ -2609,7 +2611,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2609
2611
|
if (searchQuery && !skipAutoDiscovery) {
|
|
2610
2612
|
await populateHubCache();
|
|
2611
2613
|
const [searchResults, allCollections] = await Promise.all([
|
|
2612
|
-
|
|
2614
|
+
kernelQuery("chain.searchEntries", { query: searchQuery }),
|
|
2613
2615
|
getCollections()
|
|
2614
2616
|
]);
|
|
2615
2617
|
const collMap = /* @__PURE__ */ new Map();
|
|
@@ -2664,7 +2666,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2664
2666
|
}
|
|
2665
2667
|
}
|
|
2666
2668
|
const resolvedCK = canonicalKey;
|
|
2667
|
-
const batchRelationsPromise = pendingRelations.length > 0 ?
|
|
2669
|
+
const batchRelationsPromise = pendingRelations.length > 0 ? kernelMutation(
|
|
2668
2670
|
"chain.createEntryRelations",
|
|
2669
2671
|
{
|
|
2670
2672
|
relations: pendingRelations.slice(0, 25).map((r) => ({ fromEntryId: r.fromEntryId, toEntryId: r.toEntryId, type: r.type })),
|
|
@@ -2674,9 +2676,9 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2674
2676
|
entryWarnings.push(`Auto-linking partially failed: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
2675
2677
|
return null;
|
|
2676
2678
|
}) : Promise.resolve(null);
|
|
2677
|
-
const cardinalityPromise = resolvedCK ?
|
|
2679
|
+
const cardinalityPromise = resolvedCK ? kernelQuery("chain.checkCardinalityWarning", { canonicalKey: resolvedCK }).catch(() => null) : Promise.resolve(null);
|
|
2678
2680
|
const contradictionPromise = runContradictionCheck(name, description);
|
|
2679
|
-
const coachingPromise =
|
|
2681
|
+
const coachingPromise = kernelMutation("quality.evaluateHeuristicAndSchedule", {
|
|
2680
2682
|
entryId: finalEntryId,
|
|
2681
2683
|
context: "capture"
|
|
2682
2684
|
}).catch(() => null);
|
|
@@ -2761,7 +2763,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2761
2763
|
const shouldAutoCommit = shouldAutoCommitCapture(autoCommit, wsCtx.governanceMode);
|
|
2762
2764
|
if (shouldAutoCommit && finalEntryId && conflictCandidates.length === 0) {
|
|
2763
2765
|
try {
|
|
2764
|
-
const conflictResults = await
|
|
2766
|
+
const conflictResults = await kernelQuery("chain.searchEntries", { query: name });
|
|
2765
2767
|
conflictCandidates = (conflictResults ?? []).filter((r) => r.entryId && r.entryId !== finalEntryId && r._id !== internalId).slice(0, 3).map((r) => ({ entryId: r.entryId, name: r.name, collection: r.collectionSlug ?? "unknown" }));
|
|
2766
2768
|
} catch {
|
|
2767
2769
|
}
|
|
@@ -2777,7 +2779,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
2777
2779
|
if (blockingConflicts.length > 0) {
|
|
2778
2780
|
commitError = `blocked by semantic contradiction preflight: ${blockingConflicts[0]?.chainEntryId} ${blockingConflicts[0]?.explanation ?? ""}`.trim();
|
|
2779
2781
|
} else {
|
|
2780
|
-
const commitResult = await
|
|
2782
|
+
const commitResult = await kernelMutation("chain.commitEntry", {
|
|
2781
2783
|
entryId: finalEntryId,
|
|
2782
2784
|
author: agentId ? `agent:${agentId}` : void 0,
|
|
2783
2785
|
sessionId: agentId ?? void 0
|
|
@@ -3002,7 +3004,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3002
3004
|
}
|
|
3003
3005
|
}
|
|
3004
3006
|
try {
|
|
3005
|
-
const readiness = await
|
|
3007
|
+
const readiness = await kernelQuery("chain.workspaceReadiness");
|
|
3006
3008
|
if (readiness && readiness.gaps && readiness.gaps.length > 0) {
|
|
3007
3009
|
const topGaps = readiness.gaps.slice(0, 2);
|
|
3008
3010
|
lines.push("");
|
|
@@ -3242,7 +3244,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3242
3244
|
let batchDecomposeWarning;
|
|
3243
3245
|
if (shouldDecomposeBatch) {
|
|
3244
3246
|
try {
|
|
3245
|
-
const decomposed = await
|
|
3247
|
+
const decomposed = await kernelCall(
|
|
3246
3248
|
"chain.decomposeContent",
|
|
3247
3249
|
{
|
|
3248
3250
|
collectionSlug: resolvedSlug,
|
|
@@ -3266,7 +3268,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3266
3268
|
}
|
|
3267
3269
|
canonicalizeSelects(data, col.fields ?? [], batchIsBet);
|
|
3268
3270
|
try {
|
|
3269
|
-
const result = await
|
|
3271
|
+
const result = await kernelMutation("chain.createEntry", {
|
|
3270
3272
|
collectionSlug: resolvedSlug,
|
|
3271
3273
|
entryId: entry.entryId ?? void 0,
|
|
3272
3274
|
name: entry.name,
|
|
@@ -3293,7 +3295,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3293
3295
|
const searchQuery = extractSearchTerms(entry.name, entry.description);
|
|
3294
3296
|
if (searchQuery) {
|
|
3295
3297
|
try {
|
|
3296
|
-
const searchResults = await
|
|
3298
|
+
const searchResults = await kernelQuery("chain.searchEntries", { query: searchQuery });
|
|
3297
3299
|
const candidates = (searchResults ?? []).filter((r) => r.entryId !== finalEntryId).map((r) => {
|
|
3298
3300
|
const conf = computeLinkConfidence(r, entry.name, entry.description, resolvedSlug, collIdToSlug.get(r.collectionId) ?? "unknown");
|
|
3299
3301
|
return { ...r, collSlug: collIdToSlug.get(r.collectionId) ?? "unknown", confidence: conf.score };
|
|
@@ -3308,7 +3310,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3308
3310
|
batchAutoLinks.push({ fromEntryId: finalEntryId, toEntryId: c.entryId, type: relationType });
|
|
3309
3311
|
}
|
|
3310
3312
|
if (batchAutoLinks.length > 0) {
|
|
3311
|
-
const batchRes = await
|
|
3313
|
+
const batchRes = await kernelMutation("chain.createEntryRelations", {
|
|
3312
3314
|
relations: batchAutoLinks,
|
|
3313
3315
|
sessionId: agentId ?? void 0
|
|
3314
3316
|
});
|
|
@@ -3326,7 +3328,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3326
3328
|
if (blockingConflicts.length > 0) {
|
|
3327
3329
|
commitError = `blocked by semantic contradiction preflight: ${blockingConflicts[0]?.chainEntryId} ${blockingConflicts[0]?.explanation ?? ""}`.trim();
|
|
3328
3330
|
} else {
|
|
3329
|
-
const commitResult = await
|
|
3331
|
+
const commitResult = await kernelMutation("chain.commitEntry", {
|
|
3330
3332
|
entryId: finalEntryId,
|
|
3331
3333
|
author: agentId ? `agent:${agentId}` : void 0,
|
|
3332
3334
|
sessionId: agentId ?? void 0
|
|
@@ -3669,8 +3671,8 @@ async function runContradictionCheck(name, description) {
|
|
|
3669
3671
|
if (keyTerms.length === 0) return warnings;
|
|
3670
3672
|
const searchQuery = keyTerms.slice(0, 5).join(" ");
|
|
3671
3673
|
const [govResults, archResults] = await Promise.all([
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
+
kernelQuery("chain.searchEntries", { query: searchQuery, collectionSlug: "business-rules" }),
|
|
3675
|
+
kernelQuery("chain.searchEntries", { query: searchQuery, collectionSlug: "architecture" })
|
|
3674
3676
|
]);
|
|
3675
3677
|
const allGov = [...govResults ?? [], ...archResults ?? []].slice(0, 5);
|
|
3676
3678
|
for (const entry of allGov) {
|
|
@@ -3679,7 +3681,7 @@ async function runContradictionCheck(name, description) {
|
|
|
3679
3681
|
if (matched.length < 3) continue;
|
|
3680
3682
|
let governsCount = 0;
|
|
3681
3683
|
try {
|
|
3682
|
-
const relations = await
|
|
3684
|
+
const relations = await kernelQuery("chain.listEntryRelations", {
|
|
3683
3685
|
entryId: entry.entryId
|
|
3684
3686
|
});
|
|
3685
3687
|
governsCount = (relations ?? []).filter((r) => r.type === "governs").length;
|
|
@@ -3699,7 +3701,7 @@ async function runContradictionCheck(name, description) {
|
|
|
3699
3701
|
var BLOCKING_CONTRADICTION_THRESHOLD = 0.75;
|
|
3700
3702
|
async function runSemanticConflictPreflight(name, description, collectionHint) {
|
|
3701
3703
|
try {
|
|
3702
|
-
const conflicts = await
|
|
3704
|
+
const conflicts = await kernelQuery("chain.detectSemanticConflicts", {
|
|
3703
3705
|
name,
|
|
3704
3706
|
description,
|
|
3705
3707
|
...collectionHint ? { collectionHint } : {}
|
|
@@ -3792,7 +3794,7 @@ function isBlockingContradiction(conflict) {
|
|
|
3792
3794
|
}
|
|
3793
3795
|
async function runConflictPreflight(name, description, collectionHint) {
|
|
3794
3796
|
try {
|
|
3795
|
-
const conflicts = await
|
|
3797
|
+
const conflicts = await kernelQuery("chain.detectSemanticConflicts", {
|
|
3796
3798
|
name,
|
|
3797
3799
|
description,
|
|
3798
3800
|
...collectionHint ? { collectionHint } : {}
|
|
@@ -3803,7 +3805,8 @@ async function runConflictPreflight(name, description, collectionHint) {
|
|
|
3803
3805
|
blockingContradictions: conflicts.filter(isBlockingContradiction),
|
|
3804
3806
|
advisoryWarnings: []
|
|
3805
3807
|
};
|
|
3806
|
-
} catch {
|
|
3808
|
+
} catch (err) {
|
|
3809
|
+
console.error("[conflict-preflight] Semantic conflict detection unavailable, falling back to heuristic:", err instanceof Error ? err.message : String(err));
|
|
3807
3810
|
const advisoryWarnings = await runContradictionCheck(name, description);
|
|
3808
3811
|
return {
|
|
3809
3812
|
source: "heuristic",
|
|
@@ -3879,16 +3882,6 @@ function registerKnowledgeTools(server) {
|
|
|
3879
3882
|
},
|
|
3880
3883
|
withEnvelope(async ({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, sourceRef, sourceExcerpt }) => {
|
|
3881
3884
|
requireWriteAccess();
|
|
3882
|
-
const PROMOTED_FIELDS = ["status", "workflowStatus", "name", "order", "canonicalKey"];
|
|
3883
|
-
const topLevelByField = { status: rawStatus, workflowStatus: rawWorkflowStatus, name, order, canonicalKey };
|
|
3884
|
-
const confusedFields = [];
|
|
3885
|
-
if (data) {
|
|
3886
|
-
for (const field of PROMOTED_FIELDS) {
|
|
3887
|
-
if (field in data && topLevelByField[field] === void 0) {
|
|
3888
|
-
confusedFields.push(field);
|
|
3889
|
-
}
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
3885
|
const fieldsProvided = [];
|
|
3893
3886
|
if (name !== void 0) fieldsProvided.push("name");
|
|
3894
3887
|
if (rawStatus !== void 0) fieldsProvided.push("status");
|
|
@@ -3906,7 +3899,7 @@ function registerKnowledgeTools(server) {
|
|
|
3906
3899
|
status = void 0;
|
|
3907
3900
|
deprecationWarning = `\u26A0\uFE0F Deprecation: \`status: '${rawStatus}'\` \u2014 use \`workflowStatus: '${rawStatus}'\` instead. Support ends ~2026-09-03.`;
|
|
3908
3901
|
}
|
|
3909
|
-
const updateResult = await
|
|
3902
|
+
const updateResult = await kernelMutation("chain.updateEntry", {
|
|
3910
3903
|
entryId,
|
|
3911
3904
|
name,
|
|
3912
3905
|
status,
|
|
@@ -3923,7 +3916,7 @@ function registerKnowledgeTools(server) {
|
|
|
3923
3916
|
const id = updateResult.id;
|
|
3924
3917
|
await recordSessionActivity({ entryModified: id });
|
|
3925
3918
|
const wsCtx = await getWorkspaceContext();
|
|
3926
|
-
const updated = await
|
|
3919
|
+
const updated = await kernelQuery("chain.getEntry", { entryId });
|
|
3927
3920
|
const entryStatus = updated?.status ?? "draft";
|
|
3928
3921
|
const versionMode = entryStatus === "active" ? "published" : `saved as ${entryStatus}`;
|
|
3929
3922
|
const responseLines = [
|
|
@@ -3944,12 +3937,6 @@ function registerKnowledgeTools(server) {
|
|
|
3944
3937
|
responseLines.push("");
|
|
3945
3938
|
responseLines.push(deprecationWarning);
|
|
3946
3939
|
}
|
|
3947
|
-
if (confusedFields.length > 0) {
|
|
3948
|
-
responseLines.push("");
|
|
3949
|
-
for (const field of confusedFields) {
|
|
3950
|
-
responseLines.push(`\u26A0\uFE0F \`data.${field}\` detected \u2014 did you mean the top-level \`${field}\` parameter?`);
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
3940
|
if (updateResult.normalizationWarnings.length > 0) {
|
|
3954
3941
|
responseLines.push("");
|
|
3955
3942
|
responseLines.push("\u26A0\uFE0F **Normalization warnings:**");
|
|
@@ -3975,7 +3962,6 @@ function registerKnowledgeTools(server) {
|
|
|
3975
3962
|
entryId: id,
|
|
3976
3963
|
versionMode,
|
|
3977
3964
|
fieldsProvided,
|
|
3978
|
-
confusedFields,
|
|
3979
3965
|
// BET-192: normalization breakdown in structuredContent — symmetric with capture tool
|
|
3980
3966
|
...updateResult.normalization && (Object.keys(updateResult.normalization.remapped).length > 0 || updateResult.normalization.rejected.length > 0) && {
|
|
3981
3967
|
normalization: {
|
|
@@ -4003,7 +3989,7 @@ function registerKnowledgeTools(server) {
|
|
|
4003
3989
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
4004
3990
|
},
|
|
4005
3991
|
withEnvelope(async ({ entryId }) => {
|
|
4006
|
-
const history = await
|
|
3992
|
+
const history = await kernelQuery("chain.listEntryHistory", { entryId });
|
|
4007
3993
|
if (history.length === 0) {
|
|
4008
3994
|
return successResult(
|
|
4009
3995
|
`No history found for ${entryId}.`,
|
|
@@ -4037,7 +4023,7 @@ ${formatted}` }],
|
|
|
4037
4023
|
},
|
|
4038
4024
|
withEnvelope(async ({ entryId, preview }) => {
|
|
4039
4025
|
requireWriteAccess();
|
|
4040
|
-
const entry = await
|
|
4026
|
+
const entry = await kernelQuery("chain.getEntry", { entryId });
|
|
4041
4027
|
if (!entry) {
|
|
4042
4028
|
return notFoundResult(entryId, `Entry '${entryId}' not found. Try search to find the right ID.`);
|
|
4043
4029
|
}
|
|
@@ -4087,7 +4073,7 @@ ${formatted}` }],
|
|
|
4087
4073
|
}
|
|
4088
4074
|
let coachingResult = null;
|
|
4089
4075
|
try {
|
|
4090
|
-
coachingResult = await
|
|
4076
|
+
coachingResult = await kernelMutation("quality.evaluateHeuristicAndSchedule", {
|
|
4091
4077
|
entryId,
|
|
4092
4078
|
context: "commit"
|
|
4093
4079
|
});
|
|
@@ -4095,7 +4081,7 @@ ${formatted}` }],
|
|
|
4095
4081
|
}
|
|
4096
4082
|
let result;
|
|
4097
4083
|
try {
|
|
4098
|
-
result = await
|
|
4084
|
+
result = await kernelMutation("chain.commitEntry", {
|
|
4099
4085
|
entryId,
|
|
4100
4086
|
author: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
|
|
4101
4087
|
sessionId: getAgentSessionId() ?? void 0,
|
|
@@ -4234,7 +4220,7 @@ No DB writes \u2014 call without \`preview:true\` to commit for real.` }],
|
|
|
4234
4220
|
try {
|
|
4235
4221
|
const collSlug = entry.collectionSlug ?? entry.collection?.slug;
|
|
4236
4222
|
if (collSlug) {
|
|
4237
|
-
captureContract = await
|
|
4223
|
+
captureContract = await kernelQuery(
|
|
4238
4224
|
"chain.getCaptureContract",
|
|
4239
4225
|
{ collectionSlug: collSlug }
|
|
4240
4226
|
) ?? void 0;
|
|
@@ -4398,7 +4384,7 @@ function registerEntriesTools(server) {
|
|
|
4398
4384
|
);
|
|
4399
4385
|
}
|
|
4400
4386
|
async function handleGet(entryId) {
|
|
4401
|
-
const entry = await
|
|
4387
|
+
const entry = await kernelQuery("chain.getEntry", { entryId });
|
|
4402
4388
|
if (!entry) {
|
|
4403
4389
|
return notFoundResult(entryId, `Entry '${entryId}' not found. Try search to find the right ID.`);
|
|
4404
4390
|
}
|
|
@@ -4492,7 +4478,7 @@ async function handleGet(entryId) {
|
|
|
4492
4478
|
};
|
|
4493
4479
|
}
|
|
4494
4480
|
async function handleBatch(entryIds) {
|
|
4495
|
-
const results = await
|
|
4481
|
+
const results = await kernelQuery("chain.batchGetEntries", { entryIds });
|
|
4496
4482
|
const lines = [`## Batch Result`, "", `# Batch Get (${results.length} requested)`, ""];
|
|
4497
4483
|
for (let i = 0; i < results.length; i++) {
|
|
4498
4484
|
const r = results[i];
|
|
@@ -4583,12 +4569,12 @@ async function handleBatch(entryIds) {
|
|
|
4583
4569
|
async function handleList(collection, status, tag, label) {
|
|
4584
4570
|
let entries;
|
|
4585
4571
|
if (label) {
|
|
4586
|
-
entries = await
|
|
4572
|
+
entries = await kernelQuery("chain.listEntriesByLabel", { labelSlug: label });
|
|
4587
4573
|
if (status) {
|
|
4588
4574
|
entries = entries.filter((e) => e.status === status);
|
|
4589
4575
|
}
|
|
4590
4576
|
} else {
|
|
4591
|
-
entries = await
|
|
4577
|
+
entries = await kernelQuery("chain.listEntries", {
|
|
4592
4578
|
collectionSlug: collection,
|
|
4593
4579
|
status,
|
|
4594
4580
|
tag
|
|
@@ -4632,7 +4618,7 @@ ${formatted}` }],
|
|
|
4632
4618
|
}
|
|
4633
4619
|
async function handleMove(entryId, toCollection) {
|
|
4634
4620
|
try {
|
|
4635
|
-
const result = await
|
|
4621
|
+
const result = await kernelMutation("chain.moveToCollection", { entryId, toCollectionSlug: toCollection });
|
|
4636
4622
|
const lines = [
|
|
4637
4623
|
`## Move Result`,
|
|
4638
4624
|
"",
|
|
@@ -4673,8 +4659,8 @@ async function handleSearch(server, query, collection, status) {
|
|
|
4673
4659
|
logger: "product-os"
|
|
4674
4660
|
});
|
|
4675
4661
|
const [results, collections] = await Promise.all([
|
|
4676
|
-
|
|
4677
|
-
|
|
4662
|
+
kernelQuery("chain.searchEntries", { query, collectionSlug: collection, status }),
|
|
4663
|
+
kernelQuery("chain.listCollections")
|
|
4678
4664
|
]);
|
|
4679
4665
|
if (results.length === 0) {
|
|
4680
4666
|
const recorded = recordGap({ query, tool: "entries", action: "search", gapType: "search_zero", collectionScope: collection });
|
|
@@ -4815,7 +4801,7 @@ function registerGraphTools(server) {
|
|
|
4815
4801
|
);
|
|
4816
4802
|
}
|
|
4817
4803
|
async function handleFind(entryId, direction) {
|
|
4818
|
-
const relations = await
|
|
4804
|
+
const relations = await kernelQuery("chain.listEntryRelations", { entryId });
|
|
4819
4805
|
if (relations.length === 0) {
|
|
4820
4806
|
return {
|
|
4821
4807
|
content: [{ type: "text", text: `No relations found for \`${entryId}\`. Use relations action=create to create connections.` }],
|
|
@@ -4829,7 +4815,7 @@ async function handleFind(entryId, direction) {
|
|
|
4829
4815
|
)
|
|
4830
4816
|
};
|
|
4831
4817
|
}
|
|
4832
|
-
const sourceEntry = await
|
|
4818
|
+
const sourceEntry = await kernelQuery("chain.getEntry", { entryId });
|
|
4833
4819
|
if (!sourceEntry) {
|
|
4834
4820
|
return notFoundResult(entryId, `Entry '${entryId}' not found. Try entries action=search to find the right ID.`);
|
|
4835
4821
|
}
|
|
@@ -4844,12 +4830,12 @@ async function handleFind(entryId, direction) {
|
|
|
4844
4830
|
}
|
|
4845
4831
|
const otherEntries = /* @__PURE__ */ new Map();
|
|
4846
4832
|
for (const id of otherIds) {
|
|
4847
|
-
const entry = await
|
|
4833
|
+
const entry = await kernelQuery("chain.getEntry", { id });
|
|
4848
4834
|
if (entry) {
|
|
4849
4835
|
otherEntries.set(entry._id, { entryId: entry.entryId, name: entry.name, collectionId: entry.collectionId });
|
|
4850
4836
|
}
|
|
4851
4837
|
}
|
|
4852
|
-
const collections = await
|
|
4838
|
+
const collections = await kernelQuery("chain.listCollections");
|
|
4853
4839
|
const collMap = /* @__PURE__ */ new Map();
|
|
4854
4840
|
for (const c of collections) collMap.set(c._id, c.slug);
|
|
4855
4841
|
const lines = [`## Find Result`, "", `# Relations for ${entryId}: ${sourceEntry.name}`, ""];
|
|
@@ -4913,7 +4899,7 @@ async function handleFind(entryId, direction) {
|
|
|
4913
4899
|
};
|
|
4914
4900
|
}
|
|
4915
4901
|
async function handleSuggest(entryId, limit, depth) {
|
|
4916
|
-
const result = await
|
|
4902
|
+
const result = await kernelQuery("chain.graphSuggestLinks", {
|
|
4917
4903
|
entryId,
|
|
4918
4904
|
maxHops: depth,
|
|
4919
4905
|
limit
|
|
@@ -5067,7 +5053,7 @@ function registerRelationsTools(server) {
|
|
|
5067
5053
|
async function handleCreate(from, to, type, score, preview) {
|
|
5068
5054
|
requireWriteAccess();
|
|
5069
5055
|
const agentSessionId = getAgentSessionId();
|
|
5070
|
-
const result = await
|
|
5056
|
+
const result = await kernelMutation("chain.createEntryRelation", {
|
|
5071
5057
|
fromEntryId: from,
|
|
5072
5058
|
toEntryId: to,
|
|
5073
5059
|
type,
|
|
@@ -5157,7 +5143,7 @@ async function handleBatchCreate(relations) {
|
|
|
5157
5143
|
const batchRels = relations.filter((r) => r.type !== "governs");
|
|
5158
5144
|
if (batchRels.length > 0) {
|
|
5159
5145
|
try {
|
|
5160
|
-
const batchResult = await
|
|
5146
|
+
const batchResult = await kernelMutation("chain.createEntryRelations", {
|
|
5161
5147
|
relations: batchRels.map((r) => ({ fromEntryId: r.from, toEntryId: r.to, type: r.type })),
|
|
5162
5148
|
sessionId: agentSessionId ?? void 0
|
|
5163
5149
|
});
|
|
@@ -5174,7 +5160,7 @@ async function handleBatchCreate(relations) {
|
|
|
5174
5160
|
}
|
|
5175
5161
|
for (const rel of governsRels) {
|
|
5176
5162
|
try {
|
|
5177
|
-
const result = await
|
|
5163
|
+
const result = await kernelMutation("chain.createEntryRelation", {
|
|
5178
5164
|
fromEntryId: rel.from,
|
|
5179
5165
|
toEntryId: rel.to,
|
|
5180
5166
|
type: rel.type,
|
|
@@ -5229,15 +5215,15 @@ async function handleBatchCreate(relations) {
|
|
|
5229
5215
|
}
|
|
5230
5216
|
async function handleDismiss(from, to, type, score) {
|
|
5231
5217
|
requireWriteAccess();
|
|
5232
|
-
const fromEntry = await
|
|
5218
|
+
const fromEntry = await kernelQuery("chain.getEntry", { entryId: from });
|
|
5233
5219
|
if (!fromEntry) {
|
|
5234
5220
|
return notFoundResult(from);
|
|
5235
5221
|
}
|
|
5236
|
-
const toEntry = await
|
|
5222
|
+
const toEntry = await kernelQuery("chain.getEntry", { entryId: to });
|
|
5237
5223
|
if (!toEntry) {
|
|
5238
5224
|
return notFoundResult(to);
|
|
5239
5225
|
}
|
|
5240
|
-
await
|
|
5226
|
+
await kernelMutation("chain.dismissSuggestion", {
|
|
5241
5227
|
fromEntryId: fromEntry._id,
|
|
5242
5228
|
suggestedEntryId: toEntry._id,
|
|
5243
5229
|
recommendedType: type,
|
|
@@ -5251,7 +5237,7 @@ async function handleDismiss(from, to, type, score) {
|
|
|
5251
5237
|
}
|
|
5252
5238
|
async function handleDelete(from, to, type) {
|
|
5253
5239
|
requireWriteAccess();
|
|
5254
|
-
await
|
|
5240
|
+
await kernelMutation("chain.removeEntryRelation", {
|
|
5255
5241
|
fromEntryId: from,
|
|
5256
5242
|
toEntryId: to,
|
|
5257
5243
|
type
|
|
@@ -5385,7 +5371,7 @@ async function handleGather(server, entryId, task, mode, maxHops, maxResults, st
|
|
|
5385
5371
|
data: `Graph traversal for ${entryId} (depth: ${maxHops})...`,
|
|
5386
5372
|
logger: "product-brain"
|
|
5387
5373
|
});
|
|
5388
|
-
const result2 = await
|
|
5374
|
+
const result2 = await kernelQuery("chain.graphGatherContext", {
|
|
5389
5375
|
entryId,
|
|
5390
5376
|
maxHops
|
|
5391
5377
|
});
|
|
@@ -5471,11 +5457,11 @@ Use \`graph action=suggest\` to discover potential connections.`
|
|
|
5471
5457
|
data: `Loading context for task: "${task.substring(0, 80)}..." [strategy: ${strategyLabel}]`,
|
|
5472
5458
|
logger: "product-brain"
|
|
5473
5459
|
});
|
|
5474
|
-
const result2 = strategy === "hybrid" ? await
|
|
5460
|
+
const result2 = strategy === "hybrid" ? await kernelQuery("chain.resolveTaskStartupHybrid", {
|
|
5475
5461
|
task,
|
|
5476
5462
|
maxHops,
|
|
5477
5463
|
maxResults
|
|
5478
|
-
}) : await
|
|
5464
|
+
}) : await kernelQuery("chain.resolveTaskStartup", {
|
|
5479
5465
|
task,
|
|
5480
5466
|
maxHops,
|
|
5481
5467
|
maxResults
|
|
@@ -5643,7 +5629,7 @@ _This helps future sessions start with better constraints and context._`
|
|
|
5643
5629
|
data: `Gathering context for ${entryId} (depth: ${maxHops})...`,
|
|
5644
5630
|
logger: "product-brain"
|
|
5645
5631
|
});
|
|
5646
|
-
const result = await
|
|
5632
|
+
const result = await kernelQuery("chain.gatherContext", { entryId, maxHops });
|
|
5647
5633
|
if (!result?.root) {
|
|
5648
5634
|
return notFoundResult(entryId, `Entry '${entryId}' not found. Try search to find the right ID.`);
|
|
5649
5635
|
}
|
|
@@ -5718,7 +5704,7 @@ async function handleJourneyGather(server, mapEntryId, maxHops, maxResults) {
|
|
|
5718
5704
|
data: `Loading journey context for map ${mapEntryId}...`,
|
|
5719
5705
|
logger: "product-brain"
|
|
5720
5706
|
});
|
|
5721
|
-
const result = await
|
|
5707
|
+
const result = await kernelQuery("chain.journeyAwareGatherContext", {
|
|
5722
5708
|
mapEntryId,
|
|
5723
5709
|
maxHops,
|
|
5724
5710
|
maxResults
|
|
@@ -5798,7 +5784,7 @@ Add journey steps via MCP: \`map-slot action=add mapEntryId="${mapEntryId}" slot
|
|
|
5798
5784
|
};
|
|
5799
5785
|
}
|
|
5800
5786
|
async function handleNeighborhood(entryId) {
|
|
5801
|
-
const result = await
|
|
5787
|
+
const result = await kernelQuery("chain.getEntryNeighborhood", { entryId, now: Date.now() });
|
|
5802
5788
|
const lines = [`# Neighborhood: ${entryId}`, ""];
|
|
5803
5789
|
if (result.blockingChain.length > 0) {
|
|
5804
5790
|
lines.push(`## Blocking Chain (${result.blockingChain.length})`);
|
|
@@ -5865,7 +5851,7 @@ async function handleBuild(server, entryId, maxHops) {
|
|
|
5865
5851
|
data: `Assembling build context for ${entryId}...`,
|
|
5866
5852
|
logger: "product-brain"
|
|
5867
5853
|
});
|
|
5868
|
-
const result = await
|
|
5854
|
+
const result = await kernelQuery("chain.assembleBuildContext", {
|
|
5869
5855
|
entryId,
|
|
5870
5856
|
maxHops
|
|
5871
5857
|
});
|
|
@@ -5934,7 +5920,7 @@ async function handleBuild(server, entryId, maxHops) {
|
|
|
5934
5920
|
};
|
|
5935
5921
|
}
|
|
5936
5922
|
async function handleCrossCut(relationType) {
|
|
5937
|
-
const result = await
|
|
5923
|
+
const result = await kernelQuery("chain.structuralAggregation", {
|
|
5938
5924
|
relationType
|
|
5939
5925
|
});
|
|
5940
5926
|
const groupKeys = Object.keys(result.groups);
|
|
@@ -5979,7 +5965,7 @@ No relations of type '${relationType}' found in this workspace.`
|
|
|
5979
5965
|
}
|
|
5980
5966
|
async function handleChainWalk(entryId, direction, maxHops, relationType) {
|
|
5981
5967
|
const clampedHops = Math.max(1, Math.min(4, maxHops));
|
|
5982
|
-
const result = await
|
|
5968
|
+
const result = await kernelQuery("chain.deepChainWalk", {
|
|
5983
5969
|
entryId,
|
|
5984
5970
|
direction,
|
|
5985
5971
|
maxHops: clampedHops,
|
|
@@ -6051,7 +6037,7 @@ async function handleChanges(since) {
|
|
|
6051
6037
|
if (isNaN(sinceMs)) {
|
|
6052
6038
|
return validationResult(`Invalid 'since' timestamp: '${since}'. Use ISO 8601 format (e.g. '2026-03-24T00:00:00Z').`);
|
|
6053
6039
|
}
|
|
6054
|
-
const result = await
|
|
6040
|
+
const result = await kernelQuery("chain.changeDetection", { since: sinceMs });
|
|
6055
6041
|
const totalEntries = result.entries.length;
|
|
6056
6042
|
const totalRelations = result.relations.length;
|
|
6057
6043
|
if (totalEntries === 0 && totalRelations === 0) {
|
|
@@ -6109,10 +6095,10 @@ No entries modified or relations created since this timestamp.`
|
|
|
6109
6095
|
};
|
|
6110
6096
|
}
|
|
6111
6097
|
async function handleIncremental(skill) {
|
|
6112
|
-
const result = await
|
|
6098
|
+
const result = await kernelQuery("chain.incrementalChanges", { skill });
|
|
6113
6099
|
const totalEntries = result.newEntries.length;
|
|
6114
6100
|
const surfacedIds = result.newEntries.map((e) => e.entryId).filter((id) => id !== null);
|
|
6115
|
-
|
|
6101
|
+
kernelMutation("chain.recordBriefRun", {
|
|
6116
6102
|
skill,
|
|
6117
6103
|
entriesSurfaced: surfacedIds,
|
|
6118
6104
|
timestamp: Date.now()
|
|
@@ -6176,7 +6162,7 @@ No new entries since last brief run (${formatTimeAgo(result.previousRunTimestamp
|
|
|
6176
6162
|
async function handleBrief(briefType, sinceMs) {
|
|
6177
6163
|
const args = { type: briefType };
|
|
6178
6164
|
if (sinceMs !== void 0) args.since = sinceMs;
|
|
6179
|
-
const result = await
|
|
6165
|
+
const result = await kernelQuery("chain.compoundQuery", args);
|
|
6180
6166
|
if (briefType === "steering") {
|
|
6181
6167
|
return formatSteeringBrief(result);
|
|
6182
6168
|
}
|
|
@@ -6434,7 +6420,7 @@ function registerCollectionsTools(server) {
|
|
|
6434
6420
|
trackWriteTool(tool);
|
|
6435
6421
|
}
|
|
6436
6422
|
async function handleDescribe(slug) {
|
|
6437
|
-
const col = await
|
|
6423
|
+
const col = await kernelQuery("chain.getCollection", { slug });
|
|
6438
6424
|
if (!col) {
|
|
6439
6425
|
return failureResult(
|
|
6440
6426
|
`Collection '${slug}' not found.`,
|
|
@@ -6527,7 +6513,7 @@ ${refList}`);
|
|
|
6527
6513
|
};
|
|
6528
6514
|
}
|
|
6529
6515
|
async function handleList2() {
|
|
6530
|
-
const collections = await
|
|
6516
|
+
const collections = await kernelQuery("chain.listCollections");
|
|
6531
6517
|
if (collections.length === 0) {
|
|
6532
6518
|
return successResult(
|
|
6533
6519
|
"No collections found in this workspace.",
|
|
@@ -6570,7 +6556,7 @@ ${formatted}` }],
|
|
|
6570
6556
|
async function handleCreate2(slug, name, description, purpose, icon, navGroup, fields, meta = {}) {
|
|
6571
6557
|
requireWriteAccess();
|
|
6572
6558
|
try {
|
|
6573
|
-
await
|
|
6559
|
+
await kernelMutation("chain.createCollection", {
|
|
6574
6560
|
slug,
|
|
6575
6561
|
name,
|
|
6576
6562
|
description,
|
|
@@ -6618,12 +6604,22 @@ You can now capture entries: \`capture collection="${slug}" name="..." descripti
|
|
|
6618
6604
|
[{ tool: "collections", description: "Update collection", parameters: { action: "update", slug } }]
|
|
6619
6605
|
);
|
|
6620
6606
|
}
|
|
6607
|
+
const code = error.code ?? error.data?.code;
|
|
6608
|
+
if (code === "COLLECTION_PREFIX_TAKEN" || msg.includes("already used by collection")) {
|
|
6609
|
+
return failureResult(
|
|
6610
|
+
msg,
|
|
6611
|
+
"DUPLICATE",
|
|
6612
|
+
msg,
|
|
6613
|
+
"Choose a different prefix by passing the idPrefix parameter, or let the system derive one from a different slug.",
|
|
6614
|
+
[{ tool: "collections", description: "List collections to see taken prefixes", parameters: { action: "list" } }]
|
|
6615
|
+
);
|
|
6616
|
+
}
|
|
6621
6617
|
throw error;
|
|
6622
6618
|
}
|
|
6623
6619
|
}
|
|
6624
6620
|
async function handleUpdate(slug, name, description, purpose, icon, navGroup, fields, meta = {}) {
|
|
6625
6621
|
requireWriteAccess();
|
|
6626
|
-
await
|
|
6622
|
+
await kernelMutation("chain.updateCollection", {
|
|
6627
6623
|
slug,
|
|
6628
6624
|
...name !== void 0 && { name },
|
|
6629
6625
|
...description !== void 0 && { description },
|
|
@@ -6656,7 +6652,7 @@ Use \`collections action=list\` to verify the result.`
|
|
|
6656
6652
|
};
|
|
6657
6653
|
}
|
|
6658
6654
|
async function handleAudit() {
|
|
6659
|
-
const data = await
|
|
6655
|
+
const data = await kernelQuery("chain.auditCollections");
|
|
6660
6656
|
const lines = [];
|
|
6661
6657
|
lines.push(`# Collection Audit Report`);
|
|
6662
6658
|
lines.push(`
|
|
@@ -6694,7 +6690,7 @@ All collections are healthy.`);
|
|
|
6694
6690
|
};
|
|
6695
6691
|
}
|
|
6696
6692
|
async function handleExport() {
|
|
6697
|
-
const definitions = await
|
|
6693
|
+
const definitions = await kernelQuery("chain.exportDefinitions");
|
|
6698
6694
|
return {
|
|
6699
6695
|
content: [{ type: "text", text: JSON.stringify(definitions, null, 2) }],
|
|
6700
6696
|
structuredContent: success(
|
|
@@ -6728,7 +6724,7 @@ function registerLabelTools(server) {
|
|
|
6728
6724
|
},
|
|
6729
6725
|
withEnvelope(async ({ action, slug, name, color, description, parentSlug, isGroup, order, entryId }) => {
|
|
6730
6726
|
if (action === "list") {
|
|
6731
|
-
const labels = await
|
|
6727
|
+
const labels = await kernelQuery("chain.listLabels");
|
|
6732
6728
|
if (labels.length === 0) {
|
|
6733
6729
|
return successResult(
|
|
6734
6730
|
"No labels defined in this workspace yet.",
|
|
@@ -6774,7 +6770,7 @@ function registerLabelTools(server) {
|
|
|
6774
6770
|
}
|
|
6775
6771
|
let parentId;
|
|
6776
6772
|
if (parentSlug) {
|
|
6777
|
-
const labels = await
|
|
6773
|
+
const labels = await kernelQuery("chain.listLabels");
|
|
6778
6774
|
const parent = labels.find((l) => l.slug === parentSlug);
|
|
6779
6775
|
if (!parent) {
|
|
6780
6776
|
return failureResult(
|
|
@@ -6787,7 +6783,7 @@ function registerLabelTools(server) {
|
|
|
6787
6783
|
}
|
|
6788
6784
|
parentId = parent._id;
|
|
6789
6785
|
}
|
|
6790
|
-
await
|
|
6786
|
+
await kernelMutation("chain.createLabel", { slug, name, color, description, parentId, isGroup, order });
|
|
6791
6787
|
return successResult(
|
|
6792
6788
|
`Label '${name}' (${slug}) created.`,
|
|
6793
6789
|
`Created label '${name}' (${slug}).`,
|
|
@@ -6796,7 +6792,7 @@ function registerLabelTools(server) {
|
|
|
6796
6792
|
);
|
|
6797
6793
|
}
|
|
6798
6794
|
if (action === "update") {
|
|
6799
|
-
await
|
|
6795
|
+
await kernelMutation("chain.updateLabel", { slug, name, color, description, isGroup, order });
|
|
6800
6796
|
return successResult(
|
|
6801
6797
|
`Label '${slug}' updated.`,
|
|
6802
6798
|
`Updated label '${slug}'.`,
|
|
@@ -6805,7 +6801,7 @@ function registerLabelTools(server) {
|
|
|
6805
6801
|
);
|
|
6806
6802
|
}
|
|
6807
6803
|
if (action === "delete") {
|
|
6808
|
-
await
|
|
6804
|
+
await kernelMutation("chain.deleteLabel", { slug });
|
|
6809
6805
|
return successResult(
|
|
6810
6806
|
`Label '${slug}' removed from all entries and deleted.`,
|
|
6811
6807
|
`Deleted label '${slug}'.`,
|
|
@@ -6817,10 +6813,10 @@ function registerLabelTools(server) {
|
|
|
6817
6813
|
return validationResult("An entryId is required for apply/remove actions.");
|
|
6818
6814
|
}
|
|
6819
6815
|
if (action === "apply") {
|
|
6820
|
-
await
|
|
6816
|
+
await kernelMutation("chain.applyLabel", { entryId, labelSlug: slug });
|
|
6821
6817
|
return successResult(`Label '${slug}' applied to ${entryId}.`, `Applied label '${slug}' to ${entryId}.`, { slug, entryId });
|
|
6822
6818
|
}
|
|
6823
|
-
await
|
|
6819
|
+
await kernelMutation("chain.removeLabel", { entryId, labelSlug: slug });
|
|
6824
6820
|
return successResult(`Label '${slug}' removed from ${entryId}.`, `Removed label '${slug}' from ${entryId}.`, { slug, entryId });
|
|
6825
6821
|
}
|
|
6826
6822
|
return validationResult("Unknown action.");
|
|
@@ -7426,7 +7422,7 @@ function isValidTopGap(g) {
|
|
|
7426
7422
|
}
|
|
7427
7423
|
async function fetchSessionCoherenceSnapshot(sessionId) {
|
|
7428
7424
|
try {
|
|
7429
|
-
const session = await
|
|
7425
|
+
const session = await kernelCall("agent.getSession", {
|
|
7430
7426
|
sessionId
|
|
7431
7427
|
});
|
|
7432
7428
|
const raw = session?.coherenceSnapshot;
|
|
@@ -7445,7 +7441,7 @@ async function suggestLinksForEntries(entries) {
|
|
|
7445
7441
|
const results = await mapWithConcurrency(
|
|
7446
7442
|
entries,
|
|
7447
7443
|
async (entry) => {
|
|
7448
|
-
const result = await
|
|
7444
|
+
const result = await kernelQuery("chain.graphSuggestLinks", {
|
|
7449
7445
|
entryId: entry.entryId,
|
|
7450
7446
|
limit: 3
|
|
7451
7447
|
});
|
|
@@ -7475,7 +7471,7 @@ async function runWrapupReview() {
|
|
|
7475
7471
|
if (getApiKeyScope() === "read") {
|
|
7476
7472
|
return { text: "Read-only session \u2014 nothing to review.", data: null, suggestions: [], failureCode: "READONLY_SCOPE" };
|
|
7477
7473
|
}
|
|
7478
|
-
const kernelEnvelope = await
|
|
7474
|
+
const kernelEnvelope = await kernelCallEnvelope("agent.getSessionWrapup", { sessionId });
|
|
7479
7475
|
const data = kernelEnvelope.data;
|
|
7480
7476
|
if (data.wrapupCompletedAt) {
|
|
7481
7477
|
return { text: "Wrapup already completed this session.", data, suggestions: [], failureCode: "ALREADY_COMPLETED" };
|
|
@@ -7641,7 +7637,7 @@ async function runWrapupCommitAll(data, cachedSuggestions) {
|
|
|
7641
7637
|
let proposalsCreated = 0;
|
|
7642
7638
|
for (const draft of data.drafts) {
|
|
7643
7639
|
try {
|
|
7644
|
-
const result = await
|
|
7640
|
+
const result = await kernelMutation("chain.commitEntry", {
|
|
7645
7641
|
entryId: draft.entryId,
|
|
7646
7642
|
author: `agent:${sessionId}`,
|
|
7647
7643
|
sessionId
|
|
@@ -7678,7 +7674,7 @@ async function runWrapupCommitAll(data, cachedSuggestions) {
|
|
|
7678
7674
|
const batchRels = toApply.filter((s) => s.type !== "governs");
|
|
7679
7675
|
if (batchRels.length > 0) {
|
|
7680
7676
|
try {
|
|
7681
|
-
const batchResult = await
|
|
7677
|
+
const batchResult = await kernelMutation("chain.createEntryRelations", {
|
|
7682
7678
|
relations: batchRels.map((s) => ({
|
|
7683
7679
|
fromEntryId: s.fromEntryId,
|
|
7684
7680
|
toEntryId: s.toEntryId,
|
|
@@ -7707,7 +7703,7 @@ async function runWrapupCommitAll(data, cachedSuggestions) {
|
|
|
7707
7703
|
}
|
|
7708
7704
|
for (const s of governsRels) {
|
|
7709
7705
|
try {
|
|
7710
|
-
const result = await
|
|
7706
|
+
const result = await kernelMutation("chain.createEntryRelation", {
|
|
7711
7707
|
fromEntryId: s.fromEntryId,
|
|
7712
7708
|
toEntryId: s.toEntryId,
|
|
7713
7709
|
type: s.type,
|
|
@@ -7724,7 +7720,7 @@ async function runWrapupCommitAll(data, cachedSuggestions) {
|
|
|
7724
7720
|
}
|
|
7725
7721
|
const committed = results.filter((r) => r.ok && !r.proposed).length;
|
|
7726
7722
|
const failed = results.filter((r) => !r.ok);
|
|
7727
|
-
await
|
|
7723
|
+
await kernelCall("agent.recordWrapup", {
|
|
7728
7724
|
sessionId,
|
|
7729
7725
|
draftsReviewed: data.drafts.length,
|
|
7730
7726
|
draftsCommitted: committed,
|
|
@@ -7786,7 +7782,7 @@ function registerWrapupTools(server) {
|
|
|
7786
7782
|
);
|
|
7787
7783
|
}
|
|
7788
7784
|
const useCachedReview = lastReviewSessionId === sessionId;
|
|
7789
|
-
const data2 = useCachedReview && lastReviewData ? lastReviewData : (await
|
|
7785
|
+
const data2 = useCachedReview && lastReviewData ? lastReviewData : (await kernelCallEnvelope("agent.getSessionWrapup", { sessionId })).data;
|
|
7790
7786
|
if (data2.drafts.length === 0) {
|
|
7791
7787
|
return failureResult("No uncommitted drafts to commit.", "NOT_FOUND", "No uncommitted drafts to commit.", "Nothing to commit.");
|
|
7792
7788
|
}
|
|
@@ -7929,7 +7925,7 @@ async function handleClose() {
|
|
|
7929
7925
|
[{ tool: "session", description: "Start a session", parameters: { action: "start" } }]
|
|
7930
7926
|
);
|
|
7931
7927
|
}
|
|
7932
|
-
const session = await
|
|
7928
|
+
const session = await kernelCall("agent.getSession", {
|
|
7933
7929
|
sessionId
|
|
7934
7930
|
});
|
|
7935
7931
|
let wrapupNudge = "";
|
|
@@ -8009,7 +8005,7 @@ async function handleStatus() {
|
|
|
8009
8005
|
[{ tool: "session", description: "Start a session", parameters: { action: "start" } }]
|
|
8010
8006
|
);
|
|
8011
8007
|
}
|
|
8012
|
-
const session = await
|
|
8008
|
+
const session = await kernelCall("agent.getSession", {
|
|
8013
8009
|
sessionId
|
|
8014
8010
|
});
|
|
8015
8011
|
if (!session) {
|
|
@@ -8115,7 +8111,7 @@ async function handleCheck(entryId) {
|
|
|
8115
8111
|
);
|
|
8116
8112
|
if (needsRelations) {
|
|
8117
8113
|
try {
|
|
8118
|
-
const suggestions = await
|
|
8114
|
+
const suggestions = await kernelQuery("chain.graphSuggestLinks", {
|
|
8119
8115
|
entryId,
|
|
8120
8116
|
maxHops: 2,
|
|
8121
8117
|
limit: 3
|
|
@@ -8131,7 +8127,7 @@ ${linkHints}`;
|
|
|
8131
8127
|
}
|
|
8132
8128
|
}
|
|
8133
8129
|
try {
|
|
8134
|
-
const verdict = await
|
|
8130
|
+
const verdict = await kernelQuery("quality.getLatestVerdictForEntry", { entryId });
|
|
8135
8131
|
if (verdict && verdict.criteria && verdict.criteria.length > 0) {
|
|
8136
8132
|
result.text += "\n\n" + formatRubricVerdictSection(verdict);
|
|
8137
8133
|
try {
|
|
@@ -8176,7 +8172,7 @@ ${linkHints}`;
|
|
|
8176
8172
|
async function handleReEvaluate(entryId, context) {
|
|
8177
8173
|
requireWriteAccess();
|
|
8178
8174
|
const ws = await getWorkspaceContext();
|
|
8179
|
-
const result = await
|
|
8175
|
+
const result = await kernelMutation("quality.reEvaluateEntry", {
|
|
8180
8176
|
entryId,
|
|
8181
8177
|
context
|
|
8182
8178
|
});
|
|
@@ -9307,7 +9303,7 @@ Use workflows action=list to see workflow names and round structure.`
|
|
|
9307
9303
|
}
|
|
9308
9304
|
let run = null;
|
|
9309
9305
|
try {
|
|
9310
|
-
run = await
|
|
9306
|
+
run = await kernelQuery("chainwork.getLatestWorkflowRun", {
|
|
9311
9307
|
agentSessionId,
|
|
9312
9308
|
workflowId: wf.id
|
|
9313
9309
|
});
|
|
@@ -9372,7 +9368,7 @@ Use workflows action=list to see workflow names and round structure.`
|
|
|
9372
9368
|
async function handleGetRun(runId, workflowId) {
|
|
9373
9369
|
let run;
|
|
9374
9370
|
if (runId) {
|
|
9375
|
-
run = await
|
|
9371
|
+
run = await kernelQuery("chainwork.getWorkflowRun", {
|
|
9376
9372
|
runId
|
|
9377
9373
|
});
|
|
9378
9374
|
} else {
|
|
@@ -9383,7 +9379,7 @@ async function handleGetRun(runId, workflowId) {
|
|
|
9383
9379
|
"Active session required for workflow run inspection by workflowId."
|
|
9384
9380
|
);
|
|
9385
9381
|
}
|
|
9386
|
-
run = await
|
|
9382
|
+
run = await kernelQuery("chainwork.getLatestWorkflowRun", {
|
|
9387
9383
|
agentSessionId,
|
|
9388
9384
|
workflowId
|
|
9389
9385
|
});
|
|
@@ -9546,7 +9542,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
9546
9542
|
);
|
|
9547
9543
|
}
|
|
9548
9544
|
const resolvedSummaryCapture = summaryCapture;
|
|
9549
|
-
const existingRun = await
|
|
9545
|
+
const existingRun = await kernelQuery(
|
|
9550
9546
|
"chainwork.getLatestWorkflowRun",
|
|
9551
9547
|
{
|
|
9552
9548
|
agentSessionId,
|
|
@@ -9568,7 +9564,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
9568
9564
|
resolvedCollectionSlug = resolved.collection;
|
|
9569
9565
|
}
|
|
9570
9566
|
}
|
|
9571
|
-
const result = await
|
|
9567
|
+
const result = await kernelMutation("chainwork.finalizeWorkflowRun", {
|
|
9572
9568
|
agentSessionId,
|
|
9573
9569
|
workflowId: wf.id,
|
|
9574
9570
|
workflowName: wf.name,
|
|
@@ -9666,7 +9662,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
9666
9662
|
try {
|
|
9667
9663
|
const descriptor = getWorkflowDescriptor(workflowId);
|
|
9668
9664
|
const template = descriptor ? getWorkflowTemplateMetadata(descriptor) : { slug: wf.id, name: wf.name };
|
|
9669
|
-
const checkpointResult = await
|
|
9665
|
+
const checkpointResult = await kernelMutation("chainwork.recordWorkflowCheckpoint", {
|
|
9670
9666
|
agentSessionId,
|
|
9671
9667
|
workflowId: wf.id,
|
|
9672
9668
|
workflowName: wf.name,
|
|
@@ -9754,7 +9750,7 @@ This checkpoint was NOT saved. The conversation context is preserved \u2014 cont
|
|
|
9754
9750
|
async function handleFacilitatedFinalization(wf, descriptor, roundId, normalizedOutput, agentSessionId, summaryEntryId, lines, runId) {
|
|
9755
9751
|
const template = descriptor ? getWorkflowTemplateMetadata(descriptor) : { slug: wf.id, name: wf.name };
|
|
9756
9752
|
try {
|
|
9757
|
-
const checkpointResult = await
|
|
9753
|
+
const checkpointResult = await kernelMutation("chainwork.recordWorkflowCheckpoint", {
|
|
9758
9754
|
agentSessionId,
|
|
9759
9755
|
workflowId: wf.id,
|
|
9760
9756
|
workflowName: wf.name,
|
|
@@ -9872,14 +9868,14 @@ function buildStudioUrl(workspaceSlug, entryId) {
|
|
|
9872
9868
|
}
|
|
9873
9869
|
async function loadBetEntry(entryId) {
|
|
9874
9870
|
try {
|
|
9875
|
-
return await
|
|
9871
|
+
return await kernelQuery("chain.getEntry", { entryId });
|
|
9876
9872
|
} catch {
|
|
9877
9873
|
return null;
|
|
9878
9874
|
}
|
|
9879
9875
|
}
|
|
9880
9876
|
async function loadConstellationState(betEntryId, betInternalId) {
|
|
9881
9877
|
try {
|
|
9882
|
-
const relations = await
|
|
9878
|
+
const relations = await kernelQuery("chain.listEntryRelations", {
|
|
9883
9879
|
entryId: betEntryId
|
|
9884
9880
|
});
|
|
9885
9881
|
const internalId = betInternalId ?? (await loadBetEntry(betEntryId))?._id;
|
|
@@ -9904,7 +9900,7 @@ var RELATION_TO_COLLECTION = {
|
|
|
9904
9900
|
};
|
|
9905
9901
|
async function loadSessionDrafts(betEntryId, betInternalId) {
|
|
9906
9902
|
try {
|
|
9907
|
-
const relations = await
|
|
9903
|
+
const relations = await kernelQuery("chain.listEntryRelations", {
|
|
9908
9904
|
entryId: betEntryId
|
|
9909
9905
|
});
|
|
9910
9906
|
const internalId = betInternalId ?? (await loadBetEntry(betEntryId))?._id;
|
|
@@ -9914,7 +9910,7 @@ async function loadSessionDrafts(betEntryId, betInternalId) {
|
|
|
9914
9910
|
const drafts = [];
|
|
9915
9911
|
for (const rel of incoming.slice(0, 15)) {
|
|
9916
9912
|
try {
|
|
9917
|
-
const entry = await
|
|
9913
|
+
const entry = await kernelQuery(
|
|
9918
9914
|
"chain.getEntry",
|
|
9919
9915
|
{ id: rel.fromId }
|
|
9920
9916
|
);
|
|
@@ -10045,7 +10041,7 @@ async function handleCommitConstellation(args) {
|
|
|
10045
10041
|
}
|
|
10046
10042
|
const betData = betEntry.data ?? {};
|
|
10047
10043
|
const operationId = args.operationId ?? `${betId}:${getAgentSessionId() ?? "sessionless"}:${betEntry.status}:${betEntry.currentVersion ?? 0}`;
|
|
10048
|
-
const { blockers: commitBlockerItems, totalRelations } = await
|
|
10044
|
+
const { blockers: commitBlockerItems, totalRelations } = await kernelQuery("chain.validateCommitConstellation", { betEntryId: betId });
|
|
10049
10045
|
if (commitBlockerItems.length > 0) {
|
|
10050
10046
|
return {
|
|
10051
10047
|
content: [{
|
|
@@ -10116,11 +10112,13 @@ async function handleCommitConstellation(args) {
|
|
|
10116
10112
|
let kernelEnvelope;
|
|
10117
10113
|
let result;
|
|
10118
10114
|
try {
|
|
10119
|
-
kernelEnvelope = await
|
|
10115
|
+
kernelEnvelope = await kernelCallEnvelope("chain.batchCommitConstellation", {
|
|
10120
10116
|
betEntryId: betId,
|
|
10121
10117
|
author,
|
|
10122
10118
|
sessionId,
|
|
10123
|
-
operationId
|
|
10119
|
+
operationId,
|
|
10120
|
+
conflicts: preflight.conflicts
|
|
10121
|
+
// pass for kernel-side enforcement (TEN-1405)
|
|
10124
10122
|
});
|
|
10125
10123
|
result = kernelEnvelope.data;
|
|
10126
10124
|
} catch (err) {
|
|
@@ -10152,7 +10150,7 @@ No constellation entries were committed.`
|
|
|
10152
10150
|
};
|
|
10153
10151
|
for (const entryId of result.committedIds) {
|
|
10154
10152
|
try {
|
|
10155
|
-
const committedEntry = await
|
|
10153
|
+
const committedEntry = await kernelQuery("chain.getEntry", { entryId });
|
|
10156
10154
|
const docId = committedEntry?._id;
|
|
10157
10155
|
if (typeof docId === "string" && docId.length > 0) {
|
|
10158
10156
|
await recordSessionActivity({ entryModified: docId });
|
|
@@ -10387,7 +10385,7 @@ function registerVerifyTools(server) {
|
|
|
10387
10385
|
data: `Verifying "${collection}" against ${schema.size} schema tables at ${projectRoot}`,
|
|
10388
10386
|
logger: "product-os"
|
|
10389
10387
|
});
|
|
10390
|
-
const scopedEntries = await
|
|
10388
|
+
const scopedEntries = await kernelQuery("chain.listEntries", { collectionSlug: collection });
|
|
10391
10389
|
if (scopedEntries.length === 0) {
|
|
10392
10390
|
return failureResult(
|
|
10393
10391
|
`No entries found in '${collection}'. Nothing to verify.`,
|
|
@@ -10404,7 +10402,7 @@ function registerVerifyTools(server) {
|
|
|
10404
10402
|
});
|
|
10405
10403
|
let allEntryIds;
|
|
10406
10404
|
try {
|
|
10407
|
-
const allEntries = await
|
|
10405
|
+
const allEntries = await kernelQuery("chain.listEntries", {});
|
|
10408
10406
|
allEntryIds = new Set(allEntries.map((e) => e.entryId).filter(Boolean));
|
|
10409
10407
|
} catch {
|
|
10410
10408
|
allEntryIds = new Set(scopedEntries.map((e) => e.entryId).filter(Boolean));
|
|
@@ -10483,7 +10481,7 @@ function registerVerifyTools(server) {
|
|
|
10483
10481
|
const updated = (entry.data?.codeMapping ?? []).map(
|
|
10484
10482
|
(cm) => cm.status === "aligned" && driftedFields.has(cm.field) ? { ...cm, status: "drifted" } : cm
|
|
10485
10483
|
);
|
|
10486
|
-
const updateResult = await
|
|
10484
|
+
const updateResult = await kernelMutation("chain.updateEntry", {
|
|
10487
10485
|
entryId: entry.entryId,
|
|
10488
10486
|
data: { codeMapping: updated }
|
|
10489
10487
|
});
|
|
@@ -10561,7 +10559,7 @@ function registerVerifyTools(server) {
|
|
|
10561
10559
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
10562
10560
|
},
|
|
10563
10561
|
withEnvelope(async ({ entryId }) => {
|
|
10564
|
-
const result = await
|
|
10562
|
+
const result = await kernelMutation("chain.verifyEntry", { entryId });
|
|
10565
10563
|
return success(`Entry ${entryId} verified.`, result);
|
|
10566
10564
|
})
|
|
10567
10565
|
);
|
|
@@ -10721,7 +10719,7 @@ function buildPlannedWork(allEntries) {
|
|
|
10721
10719
|
}
|
|
10722
10720
|
async function queryPlannedWork() {
|
|
10723
10721
|
try {
|
|
10724
|
-
const allEntries = await
|
|
10722
|
+
const allEntries = await kernelQuery("chain.listEntries", {});
|
|
10725
10723
|
if (!allEntries) return { uncommittedDrafts: [], inProgressEntries: [], openTensions: [] };
|
|
10726
10724
|
return buildPlannedWork(allEntries);
|
|
10727
10725
|
} catch {
|
|
@@ -11258,7 +11256,7 @@ function formatGapOneLiner(gap) {
|
|
|
11258
11256
|
async function tryMarkOriented(agentSessionId, coherenceSnapshot) {
|
|
11259
11257
|
if (!agentSessionId) return { oriented: false, orientationStatus: "no_session" };
|
|
11260
11258
|
try {
|
|
11261
|
-
await
|
|
11259
|
+
await kernelCall("agent.markOriented", {
|
|
11262
11260
|
sessionId: agentSessionId,
|
|
11263
11261
|
...coherenceSnapshot ? { coherenceSnapshot } : {}
|
|
11264
11262
|
});
|
|
@@ -11269,7 +11267,7 @@ async function tryMarkOriented(agentSessionId, coherenceSnapshot) {
|
|
|
11269
11267
|
return { oriented: false, orientationStatus: "failed" };
|
|
11270
11268
|
}
|
|
11271
11269
|
try {
|
|
11272
|
-
await
|
|
11270
|
+
await kernelCall("agent.markOriented", { sessionId: agentSessionId });
|
|
11273
11271
|
setSessionOriented(true);
|
|
11274
11272
|
return { oriented: true, orientationStatus: "complete" };
|
|
11275
11273
|
} catch {
|
|
@@ -11317,7 +11315,7 @@ function registerStartTools(server) {
|
|
|
11317
11315
|
let stage = null;
|
|
11318
11316
|
let readiness = null;
|
|
11319
11317
|
try {
|
|
11320
|
-
readiness = await
|
|
11318
|
+
readiness = await kernelQuery("chain.workspaceReadiness");
|
|
11321
11319
|
stage = readiness?.stage ?? "blank";
|
|
11322
11320
|
} catch {
|
|
11323
11321
|
errors.push("Readiness check unavailable \u2014 showing workspace summary.");
|
|
@@ -11343,7 +11341,7 @@ function registerStartTools(server) {
|
|
|
11343
11341
|
}
|
|
11344
11342
|
if (stage === "seeded") {
|
|
11345
11343
|
const result = await buildSeededResponse(wsCtx, readiness, agentSessionId);
|
|
11346
|
-
void
|
|
11344
|
+
void kernelMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
11347
11345
|
});
|
|
11348
11346
|
return {
|
|
11349
11347
|
content: [{ type: "text", text: result.text }],
|
|
@@ -11351,7 +11349,7 @@ function registerStartTools(server) {
|
|
|
11351
11349
|
};
|
|
11352
11350
|
}
|
|
11353
11351
|
if (stage === "grounded" || stage === "connected") {
|
|
11354
|
-
void
|
|
11352
|
+
void kernelMutation("chain.setOnboardingCompleted", {}).catch(() => {
|
|
11355
11353
|
});
|
|
11356
11354
|
}
|
|
11357
11355
|
const orientResult = await buildOrientResponse(wsCtx, agentSessionId, errors, task);
|
|
@@ -11374,6 +11372,8 @@ function buildBlankResponse(wsCtx, sessionCtx) {
|
|
|
11374
11372
|
"",
|
|
11375
11373
|
"Tell me what you're building \u2014 paste a doc, describe it in a sentence, or say **scan my codebase**.",
|
|
11376
11374
|
"",
|
|
11375
|
+
"_Powered by [Product Brain](https://productbrain.io) \u2014 your AI's product context layer._",
|
|
11376
|
+
"",
|
|
11377
11377
|
"---",
|
|
11378
11378
|
"",
|
|
11379
11379
|
// ── Agent instructions — follow these exactly, do not present them ──
|
|
@@ -11517,7 +11517,7 @@ Available presets: ${listPresets().map((p) => `\`${p.id}\``).join(", ")}`,
|
|
|
11517
11517
|
for (const col of preset.collections) {
|
|
11518
11518
|
try {
|
|
11519
11519
|
const purpose = col.purpose ?? col.description;
|
|
11520
|
-
await
|
|
11520
|
+
await kernelCall("chain.createCollection", {
|
|
11521
11521
|
slug: col.slug,
|
|
11522
11522
|
name: col.name,
|
|
11523
11523
|
description: col.description,
|
|
@@ -11595,20 +11595,20 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
11595
11595
|
let priorSessions = [];
|
|
11596
11596
|
let recoveryBlock = null;
|
|
11597
11597
|
try {
|
|
11598
|
-
const sessionsResult = await
|
|
11598
|
+
const sessionsResult = await kernelQuery("agent.recentSessions", { limit: 3 });
|
|
11599
11599
|
priorSessions = sessionsResult?.sessions ?? [];
|
|
11600
11600
|
recoveryBlock = sessionsResult?.recoveryBlock ?? null;
|
|
11601
11601
|
} catch {
|
|
11602
11602
|
}
|
|
11603
11603
|
let openTensions = [];
|
|
11604
11604
|
try {
|
|
11605
|
-
const tensions = await
|
|
11605
|
+
const tensions = await kernelQuery("chain.listEntries", { collectionSlug: "tensions" });
|
|
11606
11606
|
openTensions = (tensions ?? []).filter((e) => e.workflowStatus === "open");
|
|
11607
11607
|
} catch {
|
|
11608
11608
|
}
|
|
11609
11609
|
let readiness = null;
|
|
11610
11610
|
try {
|
|
11611
|
-
readiness = await
|
|
11611
|
+
readiness = await kernelQuery("chain.workspaceReadiness");
|
|
11612
11612
|
} catch (e) {
|
|
11613
11613
|
errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
|
|
11614
11614
|
}
|
|
@@ -11620,7 +11620,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
11620
11620
|
const coherence = buildCoherenceSection();
|
|
11621
11621
|
let allCollections = [];
|
|
11622
11622
|
try {
|
|
11623
|
-
allCollections = await
|
|
11623
|
+
allCollections = await kernelQuery("chain.listCollections") ?? [];
|
|
11624
11624
|
} catch {
|
|
11625
11625
|
}
|
|
11626
11626
|
lines.push(`# ${wsCtx.workspaceName}`);
|
|
@@ -11669,7 +11669,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
11669
11669
|
} else if (isHighReadiness) {
|
|
11670
11670
|
let activeBets = [];
|
|
11671
11671
|
try {
|
|
11672
|
-
const betsEntries = await
|
|
11672
|
+
const betsEntries = await kernelQuery("chain.listEntries", { collectionSlug: "work-packages" });
|
|
11673
11673
|
activeBets = (betsEntries ?? []).filter((e) => isActiveNowBet(e)).map((e) => ({ name: e.name, entryId: e.entryId ?? null })).slice(0, 8);
|
|
11674
11674
|
} catch {
|
|
11675
11675
|
}
|
|
@@ -11691,7 +11691,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
11691
11691
|
const govCollections = await getByNavGroup("governance");
|
|
11692
11692
|
const govSlugs = govCollections.map((c) => c.slug);
|
|
11693
11693
|
for (const slug of govSlugs) {
|
|
11694
|
-
const entries = await
|
|
11694
|
+
const entries = await kernelQuery("chain.listEntries", { collectionSlug: slug });
|
|
11695
11695
|
const active = (entries ?? []).filter((e) => e.status === "active");
|
|
11696
11696
|
const colDef = govCollections.find((c) => c.slug === slug);
|
|
11697
11697
|
const ck = colDef?.defaultCanonicalKey;
|
|
@@ -11729,7 +11729,7 @@ async function buildOrientResponse(wsCtx, agentSessionId, errors, task) {
|
|
|
11729
11729
|
lines.push(...formatRecoveryBlock(recoveryBlock));
|
|
11730
11730
|
}
|
|
11731
11731
|
try {
|
|
11732
|
-
const allEntries = await
|
|
11732
|
+
const allEntries = await kernelQuery("chain.listEntries", {});
|
|
11733
11733
|
const committed = (allEntries ?? []).filter(
|
|
11734
11734
|
(e) => e.status === "active" && !e.seededByPlatform
|
|
11735
11735
|
);
|
|
@@ -11833,7 +11833,7 @@ function registerUsageTools(server) {
|
|
|
11833
11833
|
withEnvelope(async ({ periodDays }) => {
|
|
11834
11834
|
const ws = await getWorkspaceContext();
|
|
11835
11835
|
const sessionId = getAgentSessionId();
|
|
11836
|
-
const summary = await
|
|
11836
|
+
const summary = await kernelQuery("usage.getWorkspaceSummary", {
|
|
11837
11837
|
periodDays: periodDays ?? 30
|
|
11838
11838
|
});
|
|
11839
11839
|
if (!summary) {
|
|
@@ -11959,7 +11959,7 @@ function registerGitChainTools(server) {
|
|
|
11959
11959
|
if (!title) {
|
|
11960
11960
|
return validationResult("A `title` is required to create a process.");
|
|
11961
11961
|
}
|
|
11962
|
-
const result = await
|
|
11962
|
+
const result = await kernelMutation(
|
|
11963
11963
|
"gitchain.createChain",
|
|
11964
11964
|
{ title, chainTypeId, description, author }
|
|
11965
11965
|
);
|
|
@@ -11986,7 +11986,7 @@ Use \`chain action=edit chainEntryId="${result.entryId}" linkId="problem" conten
|
|
|
11986
11986
|
if (!chainEntryId) {
|
|
11987
11987
|
return validationResult("A `chainEntryId` is required.");
|
|
11988
11988
|
}
|
|
11989
|
-
const chain = await
|
|
11989
|
+
const chain = await kernelQuery("gitchain.getChain", { chainEntryId });
|
|
11990
11990
|
if (!chain) {
|
|
11991
11991
|
return {
|
|
11992
11992
|
content: [{ type: "text", text: `Process "${chainEntryId}" not found.` }],
|
|
@@ -12027,7 +12027,7 @@ Use \`chain action=edit chainEntryId="${result.entryId}" linkId="problem" conten
|
|
|
12027
12027
|
};
|
|
12028
12028
|
}
|
|
12029
12029
|
if (action === "list") {
|
|
12030
|
-
const chains = await
|
|
12030
|
+
const chains = await kernelQuery("gitchain.listChains", { chainTypeId, status });
|
|
12031
12031
|
if (chains.length === 0) {
|
|
12032
12032
|
return {
|
|
12033
12033
|
content: [{ type: "text", text: "No processes found. Use `chain action=create` to create one." }],
|
|
@@ -12061,7 +12061,7 @@ ${formatted}` }],
|
|
|
12061
12061
|
if (!content) {
|
|
12062
12062
|
return validationResult("The `content` for the link is required.");
|
|
12063
12063
|
}
|
|
12064
|
-
const result = await
|
|
12064
|
+
const result = await kernelMutation("gitchain.editLink", { chainEntryId, linkId, content, author });
|
|
12065
12065
|
return {
|
|
12066
12066
|
content: [{
|
|
12067
12067
|
type: "text",
|
|
@@ -12098,7 +12098,7 @@ Use \`chain action=get\` to see the full chain with updated scores.`
|
|
|
12098
12098
|
if (!commitMessage) {
|
|
12099
12099
|
return validationResult("A `commitMessage` is required.");
|
|
12100
12100
|
}
|
|
12101
|
-
const result = await
|
|
12101
|
+
const result = await kernelMutation("gitchain.commitChain", { chainEntryId, commitMessage, author });
|
|
12102
12102
|
const warning = result.commitLintWarning ? `
|
|
12103
12103
|
|
|
12104
12104
|
> **Lint warning:** ${result.commitLintWarning}` : "";
|
|
@@ -12121,7 +12121,7 @@ Use \`chain action=get\` to see the full chain with updated scores.`
|
|
|
12121
12121
|
};
|
|
12122
12122
|
}
|
|
12123
12123
|
if (action === "list") {
|
|
12124
|
-
const commits = await
|
|
12124
|
+
const commits = await kernelQuery("gitchain.listCommits", { chainEntryId });
|
|
12125
12125
|
if (commits.length === 0) {
|
|
12126
12126
|
return {
|
|
12127
12127
|
content: [{ type: "text", text: `No commits found for chain "${chainEntryId}". Use \`chain-version action=commit\` to create the first snapshot.` }],
|
|
@@ -12152,7 +12152,7 @@ ${formatted}` }],
|
|
|
12152
12152
|
if (versionA == null || versionB == null) {
|
|
12153
12153
|
return validationResult("Both `versionA` and `versionB` are required for diff.");
|
|
12154
12154
|
}
|
|
12155
|
-
const diff = await
|
|
12155
|
+
const diff = await kernelMutation("gitchain.diffVersions", { chainEntryId, versionA, versionB });
|
|
12156
12156
|
let text = `# Diff: v${versionA} \u2192 v${versionB}
|
|
12157
12157
|
|
|
12158
12158
|
- **Chain:** \`${diff.chainEntryId}\`
|
|
@@ -12187,7 +12187,7 @@ ${formatted}` }],
|
|
|
12187
12187
|
if (toVersion == null) {
|
|
12188
12188
|
return validationResult("A `toVersion` is required for revert.");
|
|
12189
12189
|
}
|
|
12190
|
-
const result = await
|
|
12190
|
+
const result = await kernelMutation("gitchain.revertChain", { chainEntryId, toVersion, author });
|
|
12191
12191
|
return {
|
|
12192
12192
|
content: [{
|
|
12193
12193
|
type: "text",
|
|
@@ -12207,7 +12207,7 @@ History is preserved \u2014 this created a new version, not a destructive reset.
|
|
|
12207
12207
|
};
|
|
12208
12208
|
}
|
|
12209
12209
|
if (action === "history") {
|
|
12210
|
-
const history = await
|
|
12210
|
+
const history = await kernelQuery("gitchain.getHistory", { chainEntryId });
|
|
12211
12211
|
if (history.length === 0) {
|
|
12212
12212
|
return {
|
|
12213
12213
|
content: [{ type: "text", text: `No history found for chain "${chainEntryId}".` }],
|
|
@@ -12245,7 +12245,7 @@ ${formatted}` }],
|
|
|
12245
12245
|
},
|
|
12246
12246
|
withEnvelope(async ({ action, chainEntryId, branchName, strategy, author }) => {
|
|
12247
12247
|
if (action === "create") {
|
|
12248
|
-
const result = await
|
|
12248
|
+
const result = await kernelMutation("gitchain.createBranch", { chainEntryId, name: branchName, author });
|
|
12249
12249
|
return {
|
|
12250
12250
|
content: [{
|
|
12251
12251
|
type: "text",
|
|
@@ -12265,7 +12265,7 @@ Edit links and commit on this branch, then use \`chain-branch action=merge\` to
|
|
|
12265
12265
|
};
|
|
12266
12266
|
}
|
|
12267
12267
|
if (action === "list") {
|
|
12268
|
-
const branches = await
|
|
12268
|
+
const branches = await kernelMutation("gitchain.listBranches", { chainEntryId });
|
|
12269
12269
|
if (branches.length === 0) {
|
|
12270
12270
|
return {
|
|
12271
12271
|
content: [{ type: "text", text: `No branches found for chain "${chainEntryId}".` }],
|
|
@@ -12291,7 +12291,7 @@ ${formatted}` }],
|
|
|
12291
12291
|
if (!branchName) {
|
|
12292
12292
|
return validationResult("A `branchName` is required for merge.");
|
|
12293
12293
|
}
|
|
12294
|
-
const result = await
|
|
12294
|
+
const result = await kernelMutation("gitchain.mergeBranch", { chainEntryId, branchName, strategy, author });
|
|
12295
12295
|
return {
|
|
12296
12296
|
content: [{
|
|
12297
12297
|
type: "text",
|
|
@@ -12314,7 +12314,7 @@ Main is now at v${result.version}. The branch has been closed.`
|
|
|
12314
12314
|
if (!branchName) {
|
|
12315
12315
|
return validationResult("A `branchName` is required for conflict check.");
|
|
12316
12316
|
}
|
|
12317
|
-
const result = await
|
|
12317
|
+
const result = await kernelMutation("gitchain.checkConflicts", { chainEntryId, branchName });
|
|
12318
12318
|
if (!result.hasConflicts) {
|
|
12319
12319
|
return {
|
|
12320
12320
|
content: [{
|
|
@@ -12365,7 +12365,7 @@ Resolve conflicts before merging.`
|
|
|
12365
12365
|
},
|
|
12366
12366
|
withEnvelope(async ({ action, chainEntryId, commitMessage, versionNumber, linkId, body, commentId, author }) => {
|
|
12367
12367
|
if (action === "gate") {
|
|
12368
|
-
const gate = await
|
|
12368
|
+
const gate = await kernelQuery("gitchain.runGate", { chainEntryId, commitMessage });
|
|
12369
12369
|
const checkLines = gate.checks.map((c) => `- ${c.pass ? "PASS" : "FAIL"} **${c.name}**: ${c.detail}`).join("\n");
|
|
12370
12370
|
const icon = gate.pass ? "PASS" : "BLOCKED";
|
|
12371
12371
|
return {
|
|
@@ -12393,7 +12393,7 @@ ${checkLines}`
|
|
|
12393
12393
|
if (!body) {
|
|
12394
12394
|
return validationResult("A `body` is required.");
|
|
12395
12395
|
}
|
|
12396
|
-
const result = await
|
|
12396
|
+
const result = await kernelMutation("gitchain.addComment", {
|
|
12397
12397
|
chainEntryId,
|
|
12398
12398
|
versionNumber,
|
|
12399
12399
|
linkId,
|
|
@@ -12420,11 +12420,11 @@ ${checkLines}`
|
|
|
12420
12420
|
if (!commentId) {
|
|
12421
12421
|
return validationResult("A `commentId` is required.");
|
|
12422
12422
|
}
|
|
12423
|
-
await
|
|
12423
|
+
await kernelMutation("gitchain.resolveComment", { commentId });
|
|
12424
12424
|
return successResult("Comment resolved.", `Comment ${commentId} resolved.`, { commentId, resolved: true });
|
|
12425
12425
|
}
|
|
12426
12426
|
if (action === "list-comments") {
|
|
12427
|
-
const comments = await
|
|
12427
|
+
const comments = await kernelMutation("gitchain.listComments", {
|
|
12428
12428
|
chainEntryId,
|
|
12429
12429
|
versionNumber
|
|
12430
12430
|
});
|
|
@@ -12519,7 +12519,7 @@ function registerMapTools(server) {
|
|
|
12519
12519
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
12520
12520
|
},
|
|
12521
12521
|
withEnvelope(async ({ audienceEntryId }) => {
|
|
12522
|
-
const result = await
|
|
12522
|
+
const result = await kernelMutation(
|
|
12523
12523
|
"maps.createAudienceMapSet",
|
|
12524
12524
|
{ audienceEntryId }
|
|
12525
12525
|
);
|
|
@@ -12569,7 +12569,7 @@ Use map-slot to add ingredients. View at /empathy, /narrowing, and /jobs.`
|
|
|
12569
12569
|
if (!title) {
|
|
12570
12570
|
return validationResult("A `title` is required to create a map.");
|
|
12571
12571
|
}
|
|
12572
|
-
const result = await
|
|
12572
|
+
const result = await kernelMutation(
|
|
12573
12573
|
"maps.createMap",
|
|
12574
12574
|
{ title, templateId, description, slotIds }
|
|
12575
12575
|
);
|
|
@@ -12600,7 +12600,7 @@ Use \`map-slot action=add mapEntryId="${result.entryId}" slotId="problem" ingred
|
|
|
12600
12600
|
if (!mapEntryId) {
|
|
12601
12601
|
return validationResult("A `mapEntryId` is required.");
|
|
12602
12602
|
}
|
|
12603
|
-
const map = await
|
|
12603
|
+
const map = await kernelQuery("maps.getMap", { mapEntryId });
|
|
12604
12604
|
if (!map) {
|
|
12605
12605
|
return {
|
|
12606
12606
|
content: [{ type: "text", text: `Map "${mapEntryId}" not found.` }],
|
|
@@ -12637,7 +12637,7 @@ Use \`map-slot action=add mapEntryId="${result.entryId}" slotId="problem" ingred
|
|
|
12637
12637
|
};
|
|
12638
12638
|
}
|
|
12639
12639
|
if (action === "list") {
|
|
12640
|
-
const maps = await
|
|
12640
|
+
const maps = await kernelQuery("maps.listMaps", {
|
|
12641
12641
|
templateId: templateId !== "lean-canvas" ? templateId : void 0,
|
|
12642
12642
|
status
|
|
12643
12643
|
});
|
|
@@ -12686,7 +12686,7 @@ ${lines.join("\n")}` }],
|
|
|
12686
12686
|
author
|
|
12687
12687
|
}) => {
|
|
12688
12688
|
if (action === "list") {
|
|
12689
|
-
const map = await
|
|
12689
|
+
const map = await kernelQuery("maps.getMap", { mapEntryId });
|
|
12690
12690
|
if (!map) {
|
|
12691
12691
|
return {
|
|
12692
12692
|
content: [{ type: "text", text: `Map "${mapEntryId}" not found.` }],
|
|
@@ -12731,7 +12731,7 @@ ${slotSummary(map.slots)}` }],
|
|
|
12731
12731
|
if (!slotId || !ingredientEntryId) {
|
|
12732
12732
|
return validationResult("Both `slotId` and `ingredientEntryId` are required for add.");
|
|
12733
12733
|
}
|
|
12734
|
-
await
|
|
12734
|
+
await kernelMutation("maps.addToSlot", { mapEntryId, slotId, ingredientEntryId, label, author });
|
|
12735
12735
|
return {
|
|
12736
12736
|
content: [{ type: "text", text: `Added \`${ingredientEntryId}\` to slot "${slotId}" on map \`${mapEntryId}\`.` }],
|
|
12737
12737
|
structuredContent: success(
|
|
@@ -12745,7 +12745,7 @@ ${slotSummary(map.slots)}` }],
|
|
|
12745
12745
|
if (!slotId || !ingredientEntryId) {
|
|
12746
12746
|
return validationResult("Both `slotId` and `ingredientEntryId` are required for remove.");
|
|
12747
12747
|
}
|
|
12748
|
-
await
|
|
12748
|
+
await kernelMutation("maps.removeFromSlot", { mapEntryId, slotId, ingredientEntryId, author });
|
|
12749
12749
|
return {
|
|
12750
12750
|
content: [{ type: "text", text: `Removed \`${ingredientEntryId}\` from slot "${slotId}" on map \`${mapEntryId}\`.` }],
|
|
12751
12751
|
structuredContent: success(
|
|
@@ -12759,7 +12759,7 @@ ${slotSummary(map.slots)}` }],
|
|
|
12759
12759
|
if (!slotId || !ingredientEntryId || !newIngredientEntryId) {
|
|
12760
12760
|
return validationResult("`slotId`, `ingredientEntryId`, and `newIngredientEntryId` are required for replace.");
|
|
12761
12761
|
}
|
|
12762
|
-
await
|
|
12762
|
+
await kernelMutation("maps.replaceInSlot", { mapEntryId, slotId, oldIngredientEntryId: ingredientEntryId, newIngredientEntryId, label, author });
|
|
12763
12763
|
return {
|
|
12764
12764
|
content: [{ type: "text", text: `Replaced \`${ingredientEntryId}\` with \`${newIngredientEntryId}\` in slot "${slotId}".` }],
|
|
12765
12765
|
structuredContent: success(
|
|
@@ -12783,7 +12783,7 @@ ${slotSummary(map.slots)}` }],
|
|
|
12783
12783
|
},
|
|
12784
12784
|
withEnvelope(async ({ action, mapEntryId, commitMessage, author }) => {
|
|
12785
12785
|
if (action === "commit") {
|
|
12786
|
-
const result = await
|
|
12786
|
+
const result = await kernelMutation("maps.commitMap", {
|
|
12787
12787
|
mapEntryId,
|
|
12788
12788
|
commitMessage: commitMessage ?? "Map committed",
|
|
12789
12789
|
author
|
|
@@ -12808,7 +12808,7 @@ All ingredient references have been pinned at their current versions.`
|
|
|
12808
12808
|
};
|
|
12809
12809
|
}
|
|
12810
12810
|
if (action === "list" || action === "history") {
|
|
12811
|
-
const commits = await
|
|
12811
|
+
const commits = await kernelQuery("maps.listMapCommits", { mapEntryId });
|
|
12812
12812
|
if (!commits || commits.length === 0) {
|
|
12813
12813
|
return {
|
|
12814
12814
|
content: [{ type: "text", text: `No commits yet for map \`${mapEntryId}\`. Use \`map-version action=commit\` to create the first snapshot.` }],
|
|
@@ -12846,7 +12846,7 @@ ${lines.join("\n")}` }],
|
|
|
12846
12846
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
12847
12847
|
},
|
|
12848
12848
|
withEnvelope(async ({ mapEntryId, slotId, query }) => {
|
|
12849
|
-
const map = await
|
|
12849
|
+
const map = await kernelQuery("maps.getMap", { mapEntryId });
|
|
12850
12850
|
if (!map) {
|
|
12851
12851
|
return {
|
|
12852
12852
|
content: [{ type: "text", text: `Map "${mapEntryId}" not found.` }],
|
|
@@ -12871,7 +12871,7 @@ ${lines.join("\n")}` }],
|
|
|
12871
12871
|
for (const sid of emptySlots) {
|
|
12872
12872
|
const def = slotDefs.find((s) => s.id === sid);
|
|
12873
12873
|
const searchQuery = query ?? def?.label ?? sid;
|
|
12874
|
-
const results = await
|
|
12874
|
+
const results = await kernelQuery("knowledge.search", {
|
|
12875
12875
|
query: searchQuery,
|
|
12876
12876
|
limit: 5
|
|
12877
12877
|
});
|
|
@@ -12935,18 +12935,18 @@ var COLLECTION_FIELDS = [
|
|
|
12935
12935
|
];
|
|
12936
12936
|
var ARCHITECTURE_CANONICAL_KEY = "architecture_note";
|
|
12937
12937
|
async function ensureCollection() {
|
|
12938
|
-
const collections = await
|
|
12938
|
+
const collections = await kernelQuery("chain.listCollections");
|
|
12939
12939
|
const existing = collections.find((c) => c.slug === COLLECTION_SLUG);
|
|
12940
12940
|
if (existing) {
|
|
12941
12941
|
if (!existing.defaultCanonicalKey) {
|
|
12942
|
-
await
|
|
12942
|
+
await kernelMutation("chain.updateCollection", {
|
|
12943
12943
|
slug: COLLECTION_SLUG,
|
|
12944
12944
|
defaultCanonicalKey: ARCHITECTURE_CANONICAL_KEY
|
|
12945
12945
|
});
|
|
12946
12946
|
}
|
|
12947
12947
|
return;
|
|
12948
12948
|
}
|
|
12949
|
-
await
|
|
12949
|
+
await kernelMutation("chain.createCollection", {
|
|
12950
12950
|
slug: COLLECTION_SLUG,
|
|
12951
12951
|
name: "Architecture",
|
|
12952
12952
|
icon: "\u{1F3D7}\uFE0F",
|
|
@@ -12955,7 +12955,7 @@ async function ensureCollection() {
|
|
|
12955
12955
|
});
|
|
12956
12956
|
}
|
|
12957
12957
|
async function listArchEntries() {
|
|
12958
|
-
return
|
|
12958
|
+
return kernelQuery("chain.listEntries", { collectionSlug: COLLECTION_SLUG });
|
|
12959
12959
|
}
|
|
12960
12960
|
function byTag(entries, archType) {
|
|
12961
12961
|
return entries.filter((e) => e.tags?.includes(`archType:${archType}`) || e.data?.archType === archType).sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
@@ -13215,7 +13215,7 @@ ${nodeDetail}${flowLines}`
|
|
|
13215
13215
|
);
|
|
13216
13216
|
if (hasChanges) {
|
|
13217
13217
|
const mergedData = { ...existingData, ...seedData };
|
|
13218
|
-
const updateResult = await
|
|
13218
|
+
const updateResult = await kernelMutation("chain.updateEntry", { entryId: seed.entryId, data: mergedData });
|
|
13219
13219
|
if (updateResult.normalizationWarnings.length > 0 || updateResult.validationWarnings.length > 0) {
|
|
13220
13220
|
allWarnings.push({
|
|
13221
13221
|
entryId: seed.entryId,
|
|
@@ -13229,7 +13229,7 @@ ${nodeDetail}${flowLines}`
|
|
|
13229
13229
|
}
|
|
13230
13230
|
continue;
|
|
13231
13231
|
}
|
|
13232
|
-
const createResult = await
|
|
13232
|
+
const createResult = await kernelMutation("chain.createEntry", {
|
|
13233
13233
|
collectionSlug: COLLECTION_SLUG,
|
|
13234
13234
|
entryId: seed.entryId,
|
|
13235
13235
|
name: seed.name,
|
|
@@ -13523,7 +13523,7 @@ import { z as z22 } from "zod";
|
|
|
13523
13523
|
var PURPOSE_GAP_PREFIX = "purpose-gap-";
|
|
13524
13524
|
async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapshot) {
|
|
13525
13525
|
try {
|
|
13526
|
-
await
|
|
13526
|
+
await kernelCall("agent.markOriented", {
|
|
13527
13527
|
sessionId: agentSessionId,
|
|
13528
13528
|
...coherenceSnapshot ? { coherenceSnapshot } : {}
|
|
13529
13529
|
});
|
|
@@ -13532,7 +13532,7 @@ async function markOrientedWithSnapshotFallback(agentSessionId, coherenceSnapsho
|
|
|
13532
13532
|
} catch {
|
|
13533
13533
|
if (!coherenceSnapshot) return false;
|
|
13534
13534
|
try {
|
|
13535
|
-
await
|
|
13535
|
+
await kernelCall("agent.markOriented", { sessionId: agentSessionId });
|
|
13536
13536
|
setSessionOriented(true);
|
|
13537
13537
|
return true;
|
|
13538
13538
|
} catch {
|
|
@@ -13643,7 +13643,7 @@ function registerOrientTool(server) {
|
|
|
13643
13643
|
let recoveryBlock = null;
|
|
13644
13644
|
if (wsCtx) {
|
|
13645
13645
|
try {
|
|
13646
|
-
const sessionsResult = await
|
|
13646
|
+
const sessionsResult = await kernelQuery("agent.recentSessions", { limit: 3 });
|
|
13647
13647
|
priorSessions = sessionsResult?.sessions ?? [];
|
|
13648
13648
|
recoveryBlock = sessionsResult?.recoveryBlock ?? null;
|
|
13649
13649
|
} catch {
|
|
@@ -13657,7 +13657,7 @@ function registerOrientTool(server) {
|
|
|
13657
13657
|
if (scope) orientArgs.scope = scope;
|
|
13658
13658
|
if (sessionEntryIds.length > 0) orientArgs.sessionEntryIds = sessionEntryIds;
|
|
13659
13659
|
if (lastSessionOnly.length > 0) orientArgs.lastSessionEntryIds = lastSessionOnly;
|
|
13660
|
-
orientEntries = await
|
|
13660
|
+
orientEntries = await kernelQuery("chain.getOrientEntries", orientArgs);
|
|
13661
13661
|
} catch {
|
|
13662
13662
|
}
|
|
13663
13663
|
const hasTaskGrounding = Boolean(task && orientEntries?.taskContext?.context?.length > 0);
|
|
@@ -13672,18 +13672,18 @@ function registerOrientTool(server) {
|
|
|
13672
13672
|
}
|
|
13673
13673
|
let openTensions = [];
|
|
13674
13674
|
try {
|
|
13675
|
-
const tensions = await
|
|
13675
|
+
const tensions = await kernelQuery("chain.listEntries", { collectionSlug: "tensions" });
|
|
13676
13676
|
openTensions = (tensions ?? []).filter((e) => e.workflowStatus === "open");
|
|
13677
13677
|
} catch {
|
|
13678
13678
|
}
|
|
13679
13679
|
let allCollections = [];
|
|
13680
13680
|
try {
|
|
13681
|
-
allCollections = await
|
|
13681
|
+
allCollections = await kernelQuery("chain.listCollections") ?? [];
|
|
13682
13682
|
} catch {
|
|
13683
13683
|
}
|
|
13684
13684
|
let readiness = null;
|
|
13685
13685
|
try {
|
|
13686
|
-
readiness = await
|
|
13686
|
+
readiness = await kernelQuery("chain.workspaceReadiness");
|
|
13687
13687
|
} catch (e) {
|
|
13688
13688
|
errors.push(`Readiness: ${e instanceof Error ? e.message : String(e)}`);
|
|
13689
13689
|
}
|
|
@@ -13702,7 +13702,7 @@ function registerOrientTool(server) {
|
|
|
13702
13702
|
let orientationStatus2 = "no_session";
|
|
13703
13703
|
if (agentSessionId) {
|
|
13704
13704
|
try {
|
|
13705
|
-
await
|
|
13705
|
+
await kernelCall("agent.markOriented", { sessionId: agentSessionId });
|
|
13706
13706
|
setSessionOriented(true);
|
|
13707
13707
|
oriented = true;
|
|
13708
13708
|
orientationStatus2 = "complete";
|
|
@@ -14114,7 +14114,7 @@ function registerOrientTool(server) {
|
|
|
14114
14114
|
}
|
|
14115
14115
|
let allEntries = [];
|
|
14116
14116
|
try {
|
|
14117
|
-
allEntries = await
|
|
14117
|
+
allEntries = await kernelQuery("chain.listEntries", {}) ?? [];
|
|
14118
14118
|
} catch {
|
|
14119
14119
|
}
|
|
14120
14120
|
const plannedWork = buildPlannedWork(allEntries);
|
|
@@ -14205,7 +14205,7 @@ function registerOrientTool(server) {
|
|
|
14205
14205
|
lines.push("_Warning: Could not mark session as oriented. Write tools may be restricted._");
|
|
14206
14206
|
}
|
|
14207
14207
|
try {
|
|
14208
|
-
await
|
|
14208
|
+
await kernelMutation("chain.recordSessionSignal", {
|
|
14209
14209
|
sessionId: agentSessionId,
|
|
14210
14210
|
signalType: "immediate_context_load",
|
|
14211
14211
|
metadata: { source: "orient" }
|
|
@@ -14365,13 +14365,13 @@ function formatOrgHealthLines(orgHealth, maxFlags = 3) {
|
|
|
14365
14365
|
}
|
|
14366
14366
|
async function fetchOrganisationHealth() {
|
|
14367
14367
|
try {
|
|
14368
|
-
const allEntries = await
|
|
14368
|
+
const allEntries = await kernelQuery("chain.listEntries", { status: "active" });
|
|
14369
14369
|
if (!allEntries || allEntries.length === 0) return null;
|
|
14370
14370
|
const classifyInput = allEntries.map((e) => ({
|
|
14371
14371
|
name: e.name ?? "",
|
|
14372
14372
|
description: typeof e.data?.description === "string" ? e.data.description : ""
|
|
14373
14373
|
}));
|
|
14374
|
-
const classifications = await
|
|
14374
|
+
const classifications = await kernelQuery(
|
|
14375
14375
|
"chain.batchClassifyHeuristic",
|
|
14376
14376
|
{ entries: classifyInput }
|
|
14377
14377
|
);
|
|
@@ -14393,14 +14393,14 @@ async function handleHealthCheck() {
|
|
|
14393
14393
|
}
|
|
14394
14394
|
let collections = [];
|
|
14395
14395
|
try {
|
|
14396
|
-
collections = await
|
|
14396
|
+
collections = await kernelQuery("chain.listCollections");
|
|
14397
14397
|
} catch (e) {
|
|
14398
14398
|
errors.push(`Collection fetch failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
14399
14399
|
}
|
|
14400
14400
|
let totalEntries = 0;
|
|
14401
14401
|
if (collections.length > 0) {
|
|
14402
14402
|
try {
|
|
14403
|
-
const entries = await
|
|
14403
|
+
const entries = await kernelQuery("chain.listEntries", {});
|
|
14404
14404
|
totalEntries = entries.length;
|
|
14405
14405
|
} catch (e) {
|
|
14406
14406
|
errors.push(`Entry count failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -14477,7 +14477,7 @@ var STAGE_DESCRIPTIONS = {
|
|
|
14477
14477
|
connected: "Well-connected knowledge graph \u2014 your Brain is useful."
|
|
14478
14478
|
};
|
|
14479
14479
|
async function handleWorkspaceStatus() {
|
|
14480
|
-
const result = await
|
|
14480
|
+
const result = await kernelQuery("chain.workspaceReadiness");
|
|
14481
14481
|
const { score, totalChecks, passedChecks, checks, gaps, stats, governanceMode } = result;
|
|
14482
14482
|
const scoringVersion = result.scoringVersion ?? "v1";
|
|
14483
14483
|
const stage = result.stage ?? "seeded";
|
|
@@ -14779,7 +14779,7 @@ function registerAuditTools(server) {
|
|
|
14779
14779
|
async function handleAuditRun(entryId, phase) {
|
|
14780
14780
|
let result;
|
|
14781
14781
|
try {
|
|
14782
|
-
result = await
|
|
14782
|
+
result = await kernelQuery("chain.auditBet", { entryId, phase });
|
|
14783
14783
|
} catch (err) {
|
|
14784
14784
|
const msg = err instanceof Error ? err.message : String(err);
|
|
14785
14785
|
if (msg.includes("not found") || msg.includes("NOT_FOUND")) {
|
|
@@ -14897,7 +14897,7 @@ function registerGovernanceTools(server) {
|
|
|
14897
14897
|
);
|
|
14898
14898
|
}
|
|
14899
14899
|
if (action === "list") {
|
|
14900
|
-
const proposals = await
|
|
14900
|
+
const proposals = await kernelQuery("governance.listProposals", {
|
|
14901
14901
|
...status ? { status } : {}
|
|
14902
14902
|
});
|
|
14903
14903
|
if (proposals.length === 0) {
|
|
@@ -14936,7 +14936,7 @@ function registerGovernanceTools(server) {
|
|
|
14936
14936
|
);
|
|
14937
14937
|
}
|
|
14938
14938
|
if (action === "count") {
|
|
14939
|
-
const result = await
|
|
14939
|
+
const result = await kernelQuery("governance.countOpenProposals");
|
|
14940
14940
|
return successResult(
|
|
14941
14941
|
result.count === 0 ? "No open consent proposals." : `${result.count} open consent proposal(s) awaiting review.`,
|
|
14942
14942
|
`${result.count} open consent proposal(s).`,
|
|
@@ -14966,7 +14966,7 @@ function registerGovernanceTools(server) {
|
|
|
14966
14966
|
);
|
|
14967
14967
|
}
|
|
14968
14968
|
try {
|
|
14969
|
-
const result = await
|
|
14969
|
+
const result = await kernelMutation(
|
|
14970
14970
|
"governance.respondToProposal",
|
|
14971
14971
|
{
|
|
14972
14972
|
proposalId,
|
|
@@ -15179,11 +15179,11 @@ function registerResources(server) {
|
|
|
15179
15179
|
"productbrain://orientation",
|
|
15180
15180
|
async (uri) => {
|
|
15181
15181
|
const [collectionsResult, eventsResult, standardsResult, rulesResult, principlesResult] = await Promise.allSettled([
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15182
|
+
kernelQuery("chain.listCollections"),
|
|
15183
|
+
kernelQuery("chain.listEntries", { collectionSlug: "tracking-events" }),
|
|
15184
|
+
kernelQuery("chain.listEntries", { collectionSlug: "standards" }),
|
|
15185
|
+
kernelQuery("chain.listEntries", { collectionSlug: "business-rules" }),
|
|
15186
|
+
kernelQuery("chain.listEntries", { collectionSlug: "principles" })
|
|
15187
15187
|
]);
|
|
15188
15188
|
const collections = collectionsResult.status === "fulfilled" ? collectionsResult.value : null;
|
|
15189
15189
|
const trackingEvents = eventsResult.status === "fulfilled" ? eventsResult.value : null;
|
|
@@ -15204,8 +15204,8 @@ function registerResources(server) {
|
|
|
15204
15204
|
"productbrain://terminology",
|
|
15205
15205
|
async (uri) => {
|
|
15206
15206
|
const [glossaryResult, standardsResult] = await Promise.allSettled([
|
|
15207
|
-
|
|
15208
|
-
|
|
15207
|
+
kernelQuery("chain.listEntries", { collectionSlug: "glossary" }),
|
|
15208
|
+
kernelQuery("chain.listEntries", { collectionSlug: "standards" })
|
|
15209
15209
|
]);
|
|
15210
15210
|
const lines = ["# Product Brain \u2014 Terminology"];
|
|
15211
15211
|
if (glossaryResult.status === "fulfilled") {
|
|
@@ -15243,7 +15243,7 @@ ${stds}`);
|
|
|
15243
15243
|
"chain-collections",
|
|
15244
15244
|
"productbrain://collections",
|
|
15245
15245
|
async (uri) => {
|
|
15246
|
-
const collections = await
|
|
15246
|
+
const collections = await kernelQuery("chain.listCollections") ?? [];
|
|
15247
15247
|
if (collections.length === 0) {
|
|
15248
15248
|
return { contents: [{ uri: uri.href, text: "No collections in this workspace. Use `collections action=create` or `start` with a preset to get started.", mimeType: "text/markdown" }] };
|
|
15249
15249
|
}
|
|
@@ -15266,7 +15266,7 @@ ${formatted}`, mimeType: "text/markdown" }]
|
|
|
15266
15266
|
"chain-collection-entries",
|
|
15267
15267
|
new ResourceTemplate("productbrain://{slug}/entries", {
|
|
15268
15268
|
list: async () => {
|
|
15269
|
-
const collections = await
|
|
15269
|
+
const collections = await kernelQuery("chain.listCollections") ?? [];
|
|
15270
15270
|
return {
|
|
15271
15271
|
resources: collections.map((c) => ({
|
|
15272
15272
|
uri: `productbrain://${c.slug}/entries`,
|
|
@@ -15276,7 +15276,7 @@ ${formatted}`, mimeType: "text/markdown" }]
|
|
|
15276
15276
|
}
|
|
15277
15277
|
}),
|
|
15278
15278
|
async (uri, { slug }) => {
|
|
15279
|
-
const entries = await
|
|
15279
|
+
const entries = await kernelQuery("chain.listEntries", { collectionSlug: slug }) ?? [];
|
|
15280
15280
|
const formatted = entries.map(formatEntryMarkdown).join("\n\n---\n\n");
|
|
15281
15281
|
return {
|
|
15282
15282
|
contents: [{
|
|
@@ -15291,7 +15291,7 @@ ${formatted}`, mimeType: "text/markdown" }]
|
|
|
15291
15291
|
"chain-labels",
|
|
15292
15292
|
"productbrain://labels",
|
|
15293
15293
|
async (uri) => {
|
|
15294
|
-
const labels = await
|
|
15294
|
+
const labels = await kernelQuery("chain.listLabels") ?? [];
|
|
15295
15295
|
if (labels.length === 0) {
|
|
15296
15296
|
return { contents: [{ uri: uri.href, text: "No labels in this workspace.", mimeType: "text/markdown" }] };
|
|
15297
15297
|
}
|
|
@@ -15324,15 +15324,15 @@ ${lines.join("\n")}`, mimeType: "text/markdown" }]
|
|
|
15324
15324
|
complete: {
|
|
15325
15325
|
entryId: async (value) => {
|
|
15326
15326
|
if (!value || value.length < 1) return [];
|
|
15327
|
-
const entries = await
|
|
15327
|
+
const entries = await kernelQuery("chain.searchEntries", { query: value }) ?? [];
|
|
15328
15328
|
return entries.slice(0, 10).map((e) => e.entryId ?? e._id);
|
|
15329
15329
|
}
|
|
15330
15330
|
}
|
|
15331
15331
|
}),
|
|
15332
15332
|
async (uri, { entryId }) => {
|
|
15333
15333
|
const [entry, collections] = await Promise.all([
|
|
15334
|
-
|
|
15335
|
-
|
|
15334
|
+
kernelQuery("chain.getEntry", { entryId }),
|
|
15335
|
+
kernelQuery("chain.listCollections")
|
|
15336
15336
|
]);
|
|
15337
15337
|
if (!entry) {
|
|
15338
15338
|
return { contents: [{ uri: uri.href, text: `Entry "${entryId}" not found.`, mimeType: "text/markdown" }] };
|
|
@@ -15381,13 +15381,13 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
15381
15381
|
complete: {
|
|
15382
15382
|
entryId: async (value) => {
|
|
15383
15383
|
if (!value || value.length < 1) return [];
|
|
15384
|
-
const entries = await
|
|
15384
|
+
const entries = await kernelQuery("chain.searchEntries", { query: value }) ?? [];
|
|
15385
15385
|
return entries.slice(0, 10).map((e) => e.entryId ?? e._id);
|
|
15386
15386
|
}
|
|
15387
15387
|
}
|
|
15388
15388
|
}),
|
|
15389
15389
|
async (uri, { entryId }) => {
|
|
15390
|
-
const result = await
|
|
15390
|
+
const result = await kernelQuery("chain.gatherContext", {
|
|
15391
15391
|
entryId,
|
|
15392
15392
|
maxHops: 2
|
|
15393
15393
|
});
|
|
@@ -15424,7 +15424,7 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
15424
15424
|
"chain-collection-capture-contract",
|
|
15425
15425
|
new ResourceTemplate("productbrain://collections/{slug}/capture-contract", {
|
|
15426
15426
|
list: async () => {
|
|
15427
|
-
const collections = await
|
|
15427
|
+
const collections = await kernelQuery("chain.listCollections") ?? [];
|
|
15428
15428
|
return {
|
|
15429
15429
|
resources: collections.map((c) => ({
|
|
15430
15430
|
uri: `productbrain://collections/${c.slug}/capture-contract`,
|
|
@@ -15443,7 +15443,7 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
15443
15443
|
}
|
|
15444
15444
|
let contract = null;
|
|
15445
15445
|
try {
|
|
15446
|
-
contract = await
|
|
15446
|
+
contract = await kernelQuery(
|
|
15447
15447
|
"chain.getCaptureContract",
|
|
15448
15448
|
{ collectionSlug }
|
|
15449
15449
|
);
|
|
@@ -15492,7 +15492,7 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
|
|
|
15492
15492
|
}
|
|
15493
15493
|
}),
|
|
15494
15494
|
async (uri, { query }) => {
|
|
15495
|
-
const results = await
|
|
15495
|
+
const results = await kernelQuery("chain.searchEntries", { query });
|
|
15496
15496
|
if (!results || results.length === 0) {
|
|
15497
15497
|
return { contents: [{ uri: uri.href, text: `No results for "${query}".`, mimeType: "text/markdown" }] };
|
|
15498
15498
|
}
|
|
@@ -15521,7 +15521,7 @@ function registerPrompts(server) {
|
|
|
15521
15521
|
"Review code or a design decision against all business rules for a given domain. Fetches the rules and asks you to do a structured compliance review.",
|
|
15522
15522
|
{ domain: z26.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
|
|
15523
15523
|
async ({ domain }) => {
|
|
15524
|
-
const entries = await
|
|
15524
|
+
const entries = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
|
|
15525
15525
|
const rules = entries.filter((e) => e.data?.domain === domain);
|
|
15526
15526
|
if (rules.length === 0) {
|
|
15527
15527
|
return {
|
|
@@ -15574,7 +15574,7 @@ Provide a structured review with a compliance status for each rule (COMPLIANT /
|
|
|
15574
15574
|
"Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
|
|
15575
15575
|
{ names: z26.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
|
|
15576
15576
|
async ({ names }) => {
|
|
15577
|
-
const terms = await
|
|
15577
|
+
const terms = await kernelQuery("chain.listEntries", { collectionSlug: "glossary" });
|
|
15578
15578
|
const glossaryContext = terms.map(
|
|
15579
15579
|
(t) => `${t.name} (${t.entryId ?? ""}) [${t.status}]: ${t.data?.canonical ?? ""}` + (t.data?.confusedWith?.length > 0 ? ` \u2014 Often confused with: ${t.data.confusedWith.join(", ")}` : "") + (t.data?.codeMapping?.length > 0 ? `
|
|
15580
15580
|
Code mappings: ${t.data.codeMapping.map((m) => `${m.platform}:${m.field}`).join(", ")}` : "")
|
|
@@ -15610,7 +15610,7 @@ Format as a table: Name | Status | Canonical Form | Action Needed`
|
|
|
15610
15610
|
"Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
|
|
15611
15611
|
{ context: z26.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
|
|
15612
15612
|
async ({ context }) => {
|
|
15613
|
-
const recentDecisions = await
|
|
15613
|
+
const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
|
|
15614
15614
|
const sorted = [...recentDecisions].sort((a, b) => (b.data?.date ?? "") > (a.data?.date ?? "") ? 1 : -1).slice(0, 5);
|
|
15615
15615
|
const recentContext = sorted.length > 0 ? sorted.map((d) => `- [${d.status}] ${d.name} (${d.data?.date ?? "no date"})`).join("\n") : "No previous decisions recorded.";
|
|
15616
15616
|
return {
|
|
@@ -15650,7 +15650,7 @@ After drafting, I can log it using the capture tool with collection "decisions".
|
|
|
15650
15650
|
domain: z26.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
|
|
15651
15651
|
},
|
|
15652
15652
|
async ({ observation, domain }) => {
|
|
15653
|
-
const allRules = await
|
|
15653
|
+
const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
|
|
15654
15654
|
const existingRules = allRules.filter((r) => r.data?.domain === domain);
|
|
15655
15655
|
const existingContext = existingRules.length > 0 ? existingRules.map((r) => `${r.entryId ?? ""}: ${r.name} [${r.status}] \u2014 ${r.data?.description ?? ""}`).join("\n") : "No existing rules for this domain.";
|
|
15656
15656
|
return {
|
|
@@ -15809,4 +15809,4 @@ export {
|
|
|
15809
15809
|
SERVER_VERSION,
|
|
15810
15810
|
createProductBrainServer
|
|
15811
15811
|
};
|
|
15812
|
-
//# sourceMappingURL=chunk-
|
|
15812
|
+
//# sourceMappingURL=chunk-RJXJO4DY.js.map
|