@productbrain/mcp 0.0.1-beta.135 → 0.0.1-beta.139
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.
|
@@ -996,326 +996,6 @@ var FIELD_TYPE_DEFAULTS = {
|
|
|
996
996
|
"date": null
|
|
997
997
|
};
|
|
998
998
|
|
|
999
|
-
// src/lib/collectionRoutingClassifier.ts
|
|
1000
|
-
var CLASSIFIABLE_COLLECTIONS = [
|
|
1001
|
-
"decisions",
|
|
1002
|
-
"tensions",
|
|
1003
|
-
"glossary",
|
|
1004
|
-
"insights",
|
|
1005
|
-
"features",
|
|
1006
|
-
"architecture",
|
|
1007
|
-
"business-rules",
|
|
1008
|
-
// tracking-events: removed (Tier 1 Hierarchy — 0 entries, collection deprecated)
|
|
1009
|
-
"landscape",
|
|
1010
|
-
"standards",
|
|
1011
|
-
"principles",
|
|
1012
|
-
"assumptions",
|
|
1013
|
-
"work-packages",
|
|
1014
|
-
"patterns",
|
|
1015
|
-
// BET-274: Capabilities collection
|
|
1016
|
-
"capabilities"
|
|
1017
|
-
];
|
|
1018
|
-
var SIGNAL_WEIGHT = 10;
|
|
1019
|
-
var MIN_SCORE_FLOOR = 10;
|
|
1020
|
-
var MAX_MATCHES_PER_SIGNAL = 2;
|
|
1021
|
-
var MAX_REASON_COUNT = 3;
|
|
1022
|
-
var ENTRY_ID_PATTERN = /\b[A-Z]{2,}-\d+\b/g;
|
|
1023
|
-
var COLLECTION_SIGNALS = {
|
|
1024
|
-
decisions: [
|
|
1025
|
-
"decide",
|
|
1026
|
-
"decision",
|
|
1027
|
-
"chose",
|
|
1028
|
-
"chosen",
|
|
1029
|
-
"choice",
|
|
1030
|
-
"resolved",
|
|
1031
|
-
"we will",
|
|
1032
|
-
"we should",
|
|
1033
|
-
"approved",
|
|
1034
|
-
"replaces",
|
|
1035
|
-
"instead of",
|
|
1036
|
-
"go with",
|
|
1037
|
-
"criteria",
|
|
1038
|
-
"adopted",
|
|
1039
|
-
"reposition",
|
|
1040
|
-
"scoring framework",
|
|
1041
|
-
"review",
|
|
1042
|
-
// BET-124: tune recall 35%→≥50% — match abstained/misclassified fixture entries
|
|
1043
|
-
"guard level",
|
|
1044
|
-
"mcp-native",
|
|
1045
|
-
"pure functions",
|
|
1046
|
-
"intentional debt",
|
|
1047
|
-
"read allowlist",
|
|
1048
|
-
"safe-by-default",
|
|
1049
|
-
"map ingredients",
|
|
1050
|
-
"never per-seat",
|
|
1051
|
-
"neighborhood-first",
|
|
1052
|
-
"locked at",
|
|
1053
|
-
"ssot"
|
|
1054
|
-
],
|
|
1055
|
-
tensions: [
|
|
1056
|
-
"problem",
|
|
1057
|
-
"issue",
|
|
1058
|
-
"blocked",
|
|
1059
|
-
"blocker",
|
|
1060
|
-
"friction",
|
|
1061
|
-
"pain",
|
|
1062
|
-
"bottleneck",
|
|
1063
|
-
"struggle",
|
|
1064
|
-
"missing",
|
|
1065
|
-
"breaks",
|
|
1066
|
-
"regression",
|
|
1067
|
-
"unclear",
|
|
1068
|
-
"no way to",
|
|
1069
|
-
"scope creep",
|
|
1070
|
-
"coupled",
|
|
1071
|
-
"trapped",
|
|
1072
|
-
"ambiguous",
|
|
1073
|
-
"no batch",
|
|
1074
|
-
"undetectable",
|
|
1075
|
-
"coordination gap",
|
|
1076
|
-
// BET-124: tune recall 40%→≥50% — match abstained/misclassified fixture entries
|
|
1077
|
-
"methodology wall",
|
|
1078
|
-
"feature flag gap",
|
|
1079
|
-
"doesn't bridge",
|
|
1080
|
-
"cap limits",
|
|
1081
|
-
"trapped in",
|
|
1082
|
-
"no pan",
|
|
1083
|
-
"no zoom",
|
|
1084
|
-
"no interaction",
|
|
1085
|
-
"accuracy regression",
|
|
1086
|
-
"response bloat"
|
|
1087
|
-
],
|
|
1088
|
-
glossary: [
|
|
1089
|
-
"definition",
|
|
1090
|
-
"define",
|
|
1091
|
-
"term",
|
|
1092
|
-
"means",
|
|
1093
|
-
"refers to",
|
|
1094
|
-
"defined as",
|
|
1095
|
-
"is a term for",
|
|
1096
|
-
"is called",
|
|
1097
|
-
"vocabulary",
|
|
1098
|
-
"terminology",
|
|
1099
|
-
"a governance mechanism",
|
|
1100
|
-
"a workspace",
|
|
1101
|
-
"a tracked",
|
|
1102
|
-
"the atom",
|
|
1103
|
-
"the action of",
|
|
1104
|
-
"the versioned",
|
|
1105
|
-
"a field on",
|
|
1106
|
-
"one of the",
|
|
1107
|
-
"a constraint on",
|
|
1108
|
-
"a hard data",
|
|
1109
|
-
"a single",
|
|
1110
|
-
// BET-124: tune recall 46.7%→≥50% — definitional language, name-is-term pattern
|
|
1111
|
-
"constraint"
|
|
1112
|
-
],
|
|
1113
|
-
insights: [
|
|
1114
|
-
"insight",
|
|
1115
|
-
"learned",
|
|
1116
|
-
"observed",
|
|
1117
|
-
"trend",
|
|
1118
|
-
"found that",
|
|
1119
|
-
"discovery",
|
|
1120
|
-
"validates",
|
|
1121
|
-
"validated",
|
|
1122
|
-
"saturates",
|
|
1123
|
-
"convergence",
|
|
1124
|
-
"signals from",
|
|
1125
|
-
"signals",
|
|
1126
|
-
"converge",
|
|
1127
|
-
"tam",
|
|
1128
|
-
// BET-124: tune recall 26.7%→≥40% — research/data/learning language
|
|
1129
|
-
"thesis",
|
|
1130
|
-
"decay",
|
|
1131
|
-
"learnings",
|
|
1132
|
-
"aha moment",
|
|
1133
|
-
"data informs"
|
|
1134
|
-
],
|
|
1135
|
-
features: [
|
|
1136
|
-
"feature",
|
|
1137
|
-
"capability",
|
|
1138
|
-
"user can",
|
|
1139
|
-
"navigation",
|
|
1140
|
-
"palette",
|
|
1141
|
-
"modal",
|
|
1142
|
-
"smart capture",
|
|
1143
|
-
"suggest-links",
|
|
1144
|
-
"command palette",
|
|
1145
|
-
"auto-commit",
|
|
1146
|
-
"collection-optional",
|
|
1147
|
-
"organisation intelligence",
|
|
1148
|
-
"consolidation"
|
|
1149
|
-
],
|
|
1150
|
-
architecture: [
|
|
1151
|
-
"architecture",
|
|
1152
|
-
"layer",
|
|
1153
|
-
"data model",
|
|
1154
|
-
"infrastructure",
|
|
1155
|
-
"system design",
|
|
1156
|
-
"l1",
|
|
1157
|
-
"l2",
|
|
1158
|
-
"l3",
|
|
1159
|
-
"l4",
|
|
1160
|
-
"l5",
|
|
1161
|
-
"l6",
|
|
1162
|
-
"l7",
|
|
1163
|
-
"guard infrastructure",
|
|
1164
|
-
"data layer",
|
|
1165
|
-
"intelligence layer",
|
|
1166
|
-
"mcp layer",
|
|
1167
|
-
"core layer"
|
|
1168
|
-
],
|
|
1169
|
-
"business-rules": [
|
|
1170
|
-
"guard",
|
|
1171
|
-
"enforce",
|
|
1172
|
-
"integrity",
|
|
1173
|
-
"prevents",
|
|
1174
|
-
"excludes",
|
|
1175
|
-
"permitted",
|
|
1176
|
-
"policy",
|
|
1177
|
-
"feature gate",
|
|
1178
|
-
"must not",
|
|
1179
|
-
"only permitted",
|
|
1180
|
-
"closed enum",
|
|
1181
|
-
"write guard",
|
|
1182
|
-
"never imports",
|
|
1183
|
-
"requires active session",
|
|
1184
|
-
"readiness excludes"
|
|
1185
|
-
],
|
|
1186
|
-
// tracking-events: removed (Tier 1 Hierarchy — 0 entries, collection deprecated)
|
|
1187
|
-
landscape: [
|
|
1188
|
-
"competitor",
|
|
1189
|
-
"alternative tool",
|
|
1190
|
-
"alternative platform",
|
|
1191
|
-
"competing product",
|
|
1192
|
-
"landscape",
|
|
1193
|
-
"comparison"
|
|
1194
|
-
],
|
|
1195
|
-
standards: [
|
|
1196
|
-
"standard",
|
|
1197
|
-
"convention",
|
|
1198
|
-
"trunk-based",
|
|
1199
|
-
"alignment-first",
|
|
1200
|
-
"structured bet",
|
|
1201
|
-
"system fixes",
|
|
1202
|
-
"patches"
|
|
1203
|
-
],
|
|
1204
|
-
principles: [
|
|
1205
|
-
"we believe",
|
|
1206
|
-
"principle",
|
|
1207
|
-
"compounds",
|
|
1208
|
-
"philosophy",
|
|
1209
|
-
"simplicity compounds",
|
|
1210
|
-
"trust through",
|
|
1211
|
-
"evidence over",
|
|
1212
|
-
"compensate for",
|
|
1213
|
-
"honest by default"
|
|
1214
|
-
],
|
|
1215
|
-
assumptions: [
|
|
1216
|
-
"assume",
|
|
1217
|
-
"assumption",
|
|
1218
|
-
"hypothesis",
|
|
1219
|
-
"untested",
|
|
1220
|
-
"we think",
|
|
1221
|
-
"we assume",
|
|
1222
|
-
"needs validation"
|
|
1223
|
-
],
|
|
1224
|
-
patterns: [
|
|
1225
|
-
"pattern",
|
|
1226
|
-
"anti-pattern",
|
|
1227
|
-
"best practice",
|
|
1228
|
-
"reusable solution",
|
|
1229
|
-
"design pattern",
|
|
1230
|
-
"recurring solution",
|
|
1231
|
-
"template",
|
|
1232
|
-
"proven approach"
|
|
1233
|
-
],
|
|
1234
|
-
capabilities: [
|
|
1235
|
-
"capability",
|
|
1236
|
-
"capabilities",
|
|
1237
|
-
"can do",
|
|
1238
|
-
"supply-side",
|
|
1239
|
-
"product capability",
|
|
1240
|
-
"what the product does",
|
|
1241
|
-
"mature",
|
|
1242
|
-
"emerging",
|
|
1243
|
-
"declining",
|
|
1244
|
-
"platform capability",
|
|
1245
|
-
"infrastructure capability"
|
|
1246
|
-
],
|
|
1247
|
-
"work-packages": [
|
|
1248
|
-
"appetite",
|
|
1249
|
-
"elements",
|
|
1250
|
-
"no-gos",
|
|
1251
|
-
"no gos",
|
|
1252
|
-
"problem",
|
|
1253
|
-
"solution",
|
|
1254
|
-
"done when",
|
|
1255
|
-
"doneWhen",
|
|
1256
|
-
"rabbit hole",
|
|
1257
|
-
"rabbit holes",
|
|
1258
|
-
"build sequence",
|
|
1259
|
-
"build contract",
|
|
1260
|
-
"slice",
|
|
1261
|
-
"bet",
|
|
1262
|
-
"shaping",
|
|
1263
|
-
"shape up"
|
|
1264
|
-
]
|
|
1265
|
-
};
|
|
1266
|
-
function escapeRegExp(text) {
|
|
1267
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1268
|
-
}
|
|
1269
|
-
function countSignalMatches(text, signal) {
|
|
1270
|
-
const trimmed = signal.trim().toLowerCase();
|
|
1271
|
-
if (!trimmed) return 0;
|
|
1272
|
-
const words = trimmed.split(/\s+/).map(escapeRegExp);
|
|
1273
|
-
const pattern = `\\b${words.join("\\s+")}\\b`;
|
|
1274
|
-
const regex = new RegExp(pattern, "g");
|
|
1275
|
-
const matches = text.match(regex);
|
|
1276
|
-
return matches?.length ?? 0;
|
|
1277
|
-
}
|
|
1278
|
-
function classifyCollection(name, description) {
|
|
1279
|
-
const text = `${name} ${description}`.replace(ENTRY_ID_PATTERN, "").toLowerCase();
|
|
1280
|
-
const rawScores = [];
|
|
1281
|
-
for (const collection of CLASSIFIABLE_COLLECTIONS) {
|
|
1282
|
-
const signals = COLLECTION_SIGNALS[collection];
|
|
1283
|
-
const reasons = [];
|
|
1284
|
-
let score = 0;
|
|
1285
|
-
for (const signal of signals) {
|
|
1286
|
-
const matches = countSignalMatches(text, signal);
|
|
1287
|
-
if (matches <= 0) continue;
|
|
1288
|
-
const cappedMatches = Math.min(matches, MAX_MATCHES_PER_SIGNAL);
|
|
1289
|
-
score += cappedMatches * SIGNAL_WEIGHT;
|
|
1290
|
-
if (reasons.length < MAX_REASON_COUNT) {
|
|
1291
|
-
const capNote = matches > cappedMatches ? ` (capped at ${cappedMatches})` : "";
|
|
1292
|
-
reasons.push(`matched "${signal}" x${matches}${capNote}`);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
rawScores.push({ collection, score, reasons });
|
|
1296
|
-
}
|
|
1297
|
-
rawScores.sort((left, right) => right.score - left.score);
|
|
1298
|
-
const top = rawScores[0];
|
|
1299
|
-
const second = rawScores[1];
|
|
1300
|
-
if (!top || top.score < MIN_SCORE_FLOOR) return null;
|
|
1301
|
-
const margin = Math.max(0, top.score - (second?.score ?? 0));
|
|
1302
|
-
if (margin === 0 && top.score <= MIN_SCORE_FLOOR) return null;
|
|
1303
|
-
const baseConfidence = Math.min(90, top.score);
|
|
1304
|
-
const confidence = Math.min(99, baseConfidence + Math.min(20, margin));
|
|
1305
|
-
return {
|
|
1306
|
-
collection: top.collection,
|
|
1307
|
-
topConfidence: confidence,
|
|
1308
|
-
confidence,
|
|
1309
|
-
reasons: top.reasons,
|
|
1310
|
-
scoreMargin: margin,
|
|
1311
|
-
candidates: rawScores.filter((candidate) => candidate.score > 0).slice(0, 3).map((candidate) => ({
|
|
1312
|
-
collection: candidate.collection,
|
|
1313
|
-
signalScore: Math.min(99, candidate.score),
|
|
1314
|
-
confidence: Math.min(99, candidate.score)
|
|
1315
|
-
}))
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
999
|
// src/tools/smart-capture.ts
|
|
1320
1000
|
function normalizeMatchText(value) {
|
|
1321
1001
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
|
|
@@ -2021,7 +1701,9 @@ var batchCaptureSchema = z2.object({
|
|
|
2021
1701
|
description: z2.string().describe("Full context / definition"),
|
|
2022
1702
|
entryId: entryIdSchema,
|
|
2023
1703
|
data: z2.record(z2.unknown()).optional().describe("Explicit field values (e.g. urgency, status, assignee). Merged with inferred values; user-provided wins."),
|
|
2024
|
-
canonicalKey: z2.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'work_package'). Enables work-package redirect in createEntry when collection is 'chains'.")
|
|
1704
|
+
canonicalKey: z2.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'work_package'). Enables work-package redirect in createEntry when collection is 'chains'."),
|
|
1705
|
+
sourceRef: z2.string().optional().describe("URI or path of the source document backing this entry (e.g. 'meeting-2026-03-28.md', 'import://batch-5'). Stored as top-level entry field, not in data."),
|
|
1706
|
+
sourceExcerpt: z2.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Stored as top-level entry field, not in data.")
|
|
2025
1707
|
})).min(1).max(50).describe("Array of entries to capture"),
|
|
2026
1708
|
autoCommit: z2.boolean().optional().describe(
|
|
2027
1709
|
"If true, commits created entries immediately after linking. If omitted, Open mode workspaces commit by default and consensus/role modes stay draft-first."
|
|
@@ -3198,7 +2880,9 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3198
2880
|
data,
|
|
3199
2881
|
createdBy,
|
|
3200
2882
|
sessionId: agentId ?? void 0,
|
|
3201
|
-
canonicalKey: entry.canonicalKey ?? void 0
|
|
2883
|
+
canonicalKey: entry.canonicalKey ?? void 0,
|
|
2884
|
+
...entry.sourceRef ? { sourceRef: entry.sourceRef } : {},
|
|
2885
|
+
...entry.sourceExcerpt ? { sourceExcerpt: entry.sourceExcerpt } : {}
|
|
3202
2886
|
});
|
|
3203
2887
|
const internalId = result.docId;
|
|
3204
2888
|
const finalEntryId = result.entryId;
|
|
@@ -3777,7 +3461,9 @@ var updateEntrySchema = z3.object({
|
|
|
3777
3461
|
order: z3.number().optional().describe("New sort order"),
|
|
3778
3462
|
canonicalKey: z3.string().optional().describe("Semantic type (e.g. 'decision', 'tension'). Only changeable on draft/uncommitted entries."),
|
|
3779
3463
|
autoPublish: z3.boolean().optional().default(false).describe("Only true when user explicitly asks to publish. Default false = draft. Never auto-publish without user confirmation."),
|
|
3780
|
-
changeNote: z3.string().optional().describe("Strongly recommended: short human-readable rationale for WHY this change was made (e.g. 'Aligned description with F1-themed copy per BET-238'). Surfaces in activity feed and pb get. If omitted, falls back to session purpose or auto-generated field summary.")
|
|
3464
|
+
changeNote: z3.string().optional().describe("Strongly recommended: short human-readable rationale for WHY this change was made (e.g. 'Aligned description with F1-themed copy per BET-238'). Surfaces in activity feed and pb get. If omitted, falls back to session purpose or auto-generated field summary."),
|
|
3465
|
+
sourceRef: z3.string().optional().describe("URI or path of the source document backing this entry. Write-once: can only be set if currently empty."),
|
|
3466
|
+
sourceExcerpt: z3.string().optional().describe("Verbatim excerpt from the source that backs this entry's claims. Write-once: can only be set if currently empty.")
|
|
3781
3467
|
});
|
|
3782
3468
|
var getHistorySchema = z3.object({
|
|
3783
3469
|
entryId: z3.string().describe("Entry ID, e.g. 'T-SUPPLIER', 'BR-001'")
|
|
@@ -3794,7 +3480,7 @@ function registerKnowledgeTools(server) {
|
|
|
3794
3480
|
inputSchema: updateEntrySchema,
|
|
3795
3481
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
|
|
3796
3482
|
},
|
|
3797
|
-
withEnvelope(async ({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote }) => {
|
|
3483
|
+
withEnvelope(async ({ entryId, name, status: rawStatus, workflowStatus: rawWorkflowStatus, data, order, canonicalKey, autoPublish, changeNote, sourceRef, sourceExcerpt }) => {
|
|
3798
3484
|
requireWriteAccess();
|
|
3799
3485
|
const PROMOTED_FIELDS = ["status", "workflowStatus", "name", "order", "canonicalKey"];
|
|
3800
3486
|
const topLevelByField = { status: rawStatus, workflowStatus: rawWorkflowStatus, name, order, canonicalKey };
|
|
@@ -3833,7 +3519,9 @@ function registerKnowledgeTools(server) {
|
|
|
3833
3519
|
canonicalKey,
|
|
3834
3520
|
autoPublish,
|
|
3835
3521
|
changeNote,
|
|
3836
|
-
changedBy: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0
|
|
3522
|
+
changedBy: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
|
|
3523
|
+
...sourceRef ? { sourceRef } : {},
|
|
3524
|
+
...sourceExcerpt ? { sourceExcerpt } : {}
|
|
3837
3525
|
});
|
|
3838
3526
|
const id = updateResult.id;
|
|
3839
3527
|
await recordSessionActivity({ entryModified: id });
|
|
@@ -6154,7 +5842,7 @@ function formatTimeAgo(ms) {
|
|
|
6154
5842
|
|
|
6155
5843
|
// src/tools/collections.ts
|
|
6156
5844
|
import { z as z8 } from "zod";
|
|
6157
|
-
var COLLECTIONS_ACTIONS = ["list", "create", "update", "describe"];
|
|
5845
|
+
var COLLECTIONS_ACTIONS = ["list", "create", "update", "describe", "audit"];
|
|
6158
5846
|
var qualityCriterionSchema = z8.object({
|
|
6159
5847
|
field: z8.string().describe("Entry data field key this criterion applies to, e.g. 'description', 'owner'"),
|
|
6160
5848
|
rule: z8.enum(["required", "min_length", "pattern"]).describe("'required': field must be non-empty (blocks commit). 'min_length': minimum string length (warns). 'pattern': regex match (warns)."),
|
|
@@ -6180,7 +5868,7 @@ var fieldSchema = z8.object({
|
|
|
6180
5868
|
});
|
|
6181
5869
|
var collectionsSchema = z8.object({
|
|
6182
5870
|
action: z8.enum(COLLECTIONS_ACTIONS).describe(
|
|
6183
|
-
"'list': browse all collections. 'create': create a new collection. 'update': update an existing collection. 'describe': full documentation for one collection \u2014 fields, option guides, usage guidance, examples."
|
|
5871
|
+
"'list': browse all collections. 'create': create a new collection. 'update': update an existing collection. 'describe': full documentation for one collection \u2014 fields, option guides, usage guidance, examples. 'audit': health report for all collections \u2014 missing classification, icon, displayHint coverage, and field schema gaps."
|
|
6184
5872
|
),
|
|
6185
5873
|
slug: z8.string().optional().describe("URL-safe identifier for create/update, e.g. 'glossary', 'tech-debt'"),
|
|
6186
5874
|
name: z8.string().optional().describe("Display name for create, or new name for update"),
|
|
@@ -6203,7 +5891,7 @@ function registerCollectionsTools(server) {
|
|
|
6203
5891
|
"collections",
|
|
6204
5892
|
{
|
|
6205
5893
|
title: "Collections",
|
|
6206
|
-
description: "Manage knowledge collections. Four actions:\n\n- **list**: Browse all collections \u2014 glossary, business rules, tracking events, etc. Returns slug, name, description, and field schema. Use before capture to see what exists.\n- **describe**: Full documentation for a single collection. Returns field help text, option decision guides, usage guidance, examples, and cross-references. Use when you need to understand a collection's purpose, field semantics, or option values.\n- **create**: Create a new collection. Provide slug, name, and field schema. Use when setting up a workspace or tracking a new type of knowledge.\n- **update**: Update an existing collection's name, description, purpose, icon, navGroup, or fields. Only provide the fields you want to change.",
|
|
5894
|
+
description: "Manage knowledge collections. Four actions:\n\n- **list**: Browse all collections \u2014 glossary, business rules, tracking events, etc. Returns slug, name, description, and field schema. Use before capture to see what exists.\n- **describe**: Full documentation for a single collection. Returns field help text, option decision guides, usage guidance, examples, and cross-references. Use when you need to understand a collection's purpose, field semantics, or option values.\n- **create**: Create a new collection. Provide slug, name, and field schema. Use when setting up a workspace or tracking a new type of knowledge.\n- **update**: Update an existing collection's name, description, purpose, icon, navGroup, or fields. Only provide the fields you want to change.\n- **audit**: Health report for all workspace collections. Checks classification metadata, icon presence, displayHint coverage per field, and field schema gaps vs system definitions. Returns total collections, count with issues, and per-collection issue list.",
|
|
6207
5895
|
inputSchema: collectionsSchema,
|
|
6208
5896
|
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
6209
5897
|
},
|
|
@@ -6237,6 +5925,9 @@ function registerCollectionsTools(server) {
|
|
|
6237
5925
|
}
|
|
6238
5926
|
return handleUpdate(slug, name, description, purpose, icon, navGroup, fields, { defaultCanonicalKey, defaultWorkflowStatus, validWorkflowStatuses, classificationCheck, classificationPriority, qualityCriteria, usageGuidance });
|
|
6239
5927
|
}
|
|
5928
|
+
if (action === "audit") {
|
|
5929
|
+
return handleAudit();
|
|
5930
|
+
}
|
|
6240
5931
|
return unknownAction(action, COLLECTIONS_ACTIONS);
|
|
6241
5932
|
});
|
|
6242
5933
|
})
|
|
@@ -6465,6 +6156,44 @@ Use \`collections action=list\` to verify the result.`
|
|
|
6465
6156
|
)
|
|
6466
6157
|
};
|
|
6467
6158
|
}
|
|
6159
|
+
async function handleAudit() {
|
|
6160
|
+
const data = await mcpQuery("chain.auditCollections");
|
|
6161
|
+
const lines = [];
|
|
6162
|
+
lines.push(`# Collection Audit Report`);
|
|
6163
|
+
lines.push(`
|
|
6164
|
+
**Total:** ${data.total} \xB7 **Healthy:** ${data.healthy} \xB7 **With issues:** ${data.withIssues}`);
|
|
6165
|
+
if (data.withIssues === 0) {
|
|
6166
|
+
lines.push(`
|
|
6167
|
+
All collections are healthy.`);
|
|
6168
|
+
} else {
|
|
6169
|
+
const problematic = data.collections.filter((c) => c.issues.length > 0);
|
|
6170
|
+
lines.push(`
|
|
6171
|
+
## Collections With Issues
|
|
6172
|
+
`);
|
|
6173
|
+
for (const col of problematic) {
|
|
6174
|
+
const icon = col.icon ?? "\u2014";
|
|
6175
|
+
lines.push(`### ${icon} ${col.name} (\`${col.slug}\`) \u2014 ${col.issues.length} issue(s)`);
|
|
6176
|
+
for (const issue of col.issues) {
|
|
6177
|
+
lines.push(`- **[${issue.code}]** ${issue.message}`);
|
|
6178
|
+
}
|
|
6179
|
+
lines.push("");
|
|
6180
|
+
}
|
|
6181
|
+
}
|
|
6182
|
+
const healthyCollections = data.collections.filter((c) => c.issues.length === 0);
|
|
6183
|
+
if (healthyCollections.length > 0) {
|
|
6184
|
+
lines.push(`
|
|
6185
|
+
## Healthy Collections
|
|
6186
|
+
`);
|
|
6187
|
+
lines.push(healthyCollections.map((c) => `- ${c.icon ?? "\u2014"} \`${c.slug}\``).join("\n"));
|
|
6188
|
+
}
|
|
6189
|
+
return {
|
|
6190
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
6191
|
+
structuredContent: success(
|
|
6192
|
+
`Audit complete. ${data.total} collections: ${data.healthy} healthy, ${data.withIssues} with issues.`,
|
|
6193
|
+
data
|
|
6194
|
+
)
|
|
6195
|
+
};
|
|
6196
|
+
}
|
|
6468
6197
|
|
|
6469
6198
|
// src/tools/labels.ts
|
|
6470
6199
|
import { z as z9 } from "zod";
|
|
@@ -6603,14 +6332,7 @@ import { z as z10 } from "zod";
|
|
|
6603
6332
|
// src/lib/coherence/data.ts
|
|
6604
6333
|
var REGISTRY_MANIFEST = [
|
|
6605
6334
|
// ── Canonical UI registries ──────────────────────────────────────
|
|
6606
|
-
|
|
6607
|
-
id: "ui-colors",
|
|
6608
|
-
path: "src/lib/utils/collection-colors.ts",
|
|
6609
|
-
exportName: "COLLECTION_COLORS",
|
|
6610
|
-
description: "CSS color mapping for UI components",
|
|
6611
|
-
expectedCoverage: "curated",
|
|
6612
|
-
keyExtraction: "object-keys"
|
|
6613
|
-
},
|
|
6335
|
+
// BET-143 Slice 4: ui-colors removed — color is now a field on collection docs (schema.ts).
|
|
6614
6336
|
{
|
|
6615
6337
|
id: "routes",
|
|
6616
6338
|
path: "src/lib/navigation.ts",
|
|
@@ -6627,56 +6349,11 @@ var REGISTRY_MANIFEST = [
|
|
|
6627
6349
|
expectedCoverage: "curated",
|
|
6628
6350
|
keyExtraction: "object-keys"
|
|
6629
6351
|
},
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
path: "src/lib/navigation.ts",
|
|
6633
|
-
exportName: "SIDEBAR_COLLECTION_SLUGS",
|
|
6634
|
-
description: "Collection slugs with dedicated sidebar entries",
|
|
6635
|
-
expectedCoverage: "subset",
|
|
6636
|
-
keyExtraction: "set-values"
|
|
6637
|
-
},
|
|
6638
|
-
{
|
|
6639
|
-
id: "display-fields",
|
|
6640
|
-
path: "src/lib/components/EntryPreviewModal.svelte",
|
|
6641
|
-
exportName: "DISPLAY_FIELDS",
|
|
6642
|
-
description: "Fields displayed in entry preview modal per collection",
|
|
6643
|
-
expectedCoverage: "curated",
|
|
6644
|
-
keyExtraction: "object-keys"
|
|
6645
|
-
},
|
|
6646
|
-
// ── Brain Chat registries ────────────────────────────────────────
|
|
6647
|
-
{
|
|
6648
|
-
id: "brain-colors",
|
|
6649
|
-
path: "src/lib/components/brain/brain-types.ts",
|
|
6650
|
-
exportName: "COLLECTION_COLORS",
|
|
6651
|
-
description: "Brain Chat collection color palette",
|
|
6652
|
-
expectedCoverage: "subset",
|
|
6653
|
-
keyExtraction: "object-keys"
|
|
6654
|
-
},
|
|
6655
|
-
{
|
|
6656
|
-
id: "brain-icons",
|
|
6657
|
-
path: "src/lib/components/brain/brain-types.ts",
|
|
6658
|
-
exportName: "COLLECTION_ICONS",
|
|
6659
|
-
description: "Brain Chat collection icons",
|
|
6660
|
-
expectedCoverage: "subset",
|
|
6661
|
-
keyExtraction: "object-keys"
|
|
6662
|
-
},
|
|
6352
|
+
// BET-280 S3: display-fields removed — DISPLAY_FIELDS constant deleted, field display is now schema-driven.
|
|
6353
|
+
// BET-280 S3: brain-icons removed — COLLECTION_ICONS unexported, getCollectionIcon() is a local rendering fallback only.
|
|
6663
6354
|
// ── Graph visualization registries ───────────────────────────────
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
path: "src/lib/utils/graphToVisNetwork.ts",
|
|
6667
|
-
exportName: "GRAPH_COLLECTION_COLORS",
|
|
6668
|
-
description: "Graph visualization hex color palette",
|
|
6669
|
-
expectedCoverage: "subset",
|
|
6670
|
-
keyExtraction: "object-keys"
|
|
6671
|
-
},
|
|
6672
|
-
{
|
|
6673
|
-
id: "graph-type-colors",
|
|
6674
|
-
path: "src/lib/components/graph/graph.types.ts",
|
|
6675
|
-
exportName: "COLLECTION_COLORS",
|
|
6676
|
-
description: "Chain Graph collection colors (distinct palette)",
|
|
6677
|
-
expectedCoverage: "subset",
|
|
6678
|
-
keyExtraction: "object-keys"
|
|
6679
|
-
},
|
|
6355
|
+
// BET-143 Slice 4: graph-colors and graph-type-colors removed.
|
|
6356
|
+
// Graph rendering uses local fallback palettes (canvas needs resolved hex/CSS vars, not DB reads).
|
|
6680
6357
|
// ── Cortex registries ────────────────────────────────────────────
|
|
6681
6358
|
{
|
|
6682
6359
|
id: "renderers",
|
|
@@ -6698,71 +6375,17 @@ var REGISTRY_MANIFEST = [
|
|
|
6698
6375
|
// TEN-598: default-collections removed. Collection definitions live in system_collection_definitions (DB).
|
|
6699
6376
|
];
|
|
6700
6377
|
var COLLECTION_REGISTRY_RULES = [
|
|
6701
|
-
// ── Coverage: downstream registries should cover important collections ──
|
|
6702
|
-
{
|
|
6703
|
-
id: "coverage-ui-colors",
|
|
6704
|
-
type: "coverage",
|
|
6705
|
-
description: "UI colors should cover collections that have sidebar routes",
|
|
6706
|
-
subject: "ui-colors",
|
|
6707
|
-
reference: "routes"
|
|
6708
|
-
},
|
|
6709
6378
|
// ── Subset: specialized registries should only reference known collections ──
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
subject: "brain-colors",
|
|
6715
|
-
reference: "classification-map"
|
|
6716
|
-
},
|
|
6717
|
-
{
|
|
6718
|
-
id: "subset-brain-icons",
|
|
6719
|
-
type: "subset",
|
|
6720
|
-
description: "Brain icons should only reference classified collections",
|
|
6721
|
-
subject: "brain-icons",
|
|
6722
|
-
reference: "classification-map"
|
|
6723
|
-
},
|
|
6379
|
+
// BET-143 Slice 4: brain-colors, graph-colors, graph-type-colors rules removed —
|
|
6380
|
+
// those registries were deleted when color moved to collection docs.
|
|
6381
|
+
// BET-280 S3: brain-icons rule removed — COLLECTION_ICONS unexported, no longer a registry.
|
|
6382
|
+
// BET-280 S3: display-fields rule removed — DISPLAY_FIELDS deleted, field display is schema-driven.
|
|
6724
6383
|
{
|
|
6725
6384
|
id: "subset-renderers",
|
|
6726
6385
|
type: "subset",
|
|
6727
6386
|
description: "Renderers should only reference classified collections",
|
|
6728
6387
|
subject: "renderers",
|
|
6729
6388
|
reference: "classification-map"
|
|
6730
|
-
},
|
|
6731
|
-
{
|
|
6732
|
-
id: "subset-display-fields",
|
|
6733
|
-
type: "subset",
|
|
6734
|
-
description: "Display fields should only reference classified collections",
|
|
6735
|
-
subject: "display-fields",
|
|
6736
|
-
reference: "classification-map"
|
|
6737
|
-
},
|
|
6738
|
-
{
|
|
6739
|
-
id: "subset-graph-colors",
|
|
6740
|
-
type: "subset",
|
|
6741
|
-
description: "Graph colors should only reference classified collections",
|
|
6742
|
-
subject: "graph-colors",
|
|
6743
|
-
reference: "classification-map"
|
|
6744
|
-
},
|
|
6745
|
-
{
|
|
6746
|
-
id: "subset-graph-type-colors",
|
|
6747
|
-
type: "subset",
|
|
6748
|
-
description: "Graph type colors should only reference classified collections",
|
|
6749
|
-
subject: "graph-type-colors",
|
|
6750
|
-
reference: "classification-map"
|
|
6751
|
-
},
|
|
6752
|
-
// ── Implication: presence in one registry implies presence in another ──
|
|
6753
|
-
{
|
|
6754
|
-
id: "implication-routes-need-colors",
|
|
6755
|
-
type: "implication",
|
|
6756
|
-
description: "Collections with routes should also have UI colors",
|
|
6757
|
-
subject: "routes",
|
|
6758
|
-
reference: "ui-colors"
|
|
6759
|
-
},
|
|
6760
|
-
{
|
|
6761
|
-
id: "implication-sidebar-needs-route",
|
|
6762
|
-
type: "implication",
|
|
6763
|
-
description: "Sidebar collections should have a route defined",
|
|
6764
|
-
subject: "sidebar-collections",
|
|
6765
|
-
reference: "routes"
|
|
6766
6389
|
}
|
|
6767
6390
|
];
|
|
6768
6391
|
|
|
@@ -13323,9 +12946,23 @@ function extractSessionEntryIds(priorSessions) {
|
|
|
13323
12946
|
}
|
|
13324
12947
|
return { all, lastSessionOnly };
|
|
13325
12948
|
}
|
|
12949
|
+
var VALID_TASK_DOMAINS = [
|
|
12950
|
+
"auth",
|
|
12951
|
+
"governance",
|
|
12952
|
+
"architecture",
|
|
12953
|
+
"product",
|
|
12954
|
+
"data-foundation",
|
|
12955
|
+
"chainwork",
|
|
12956
|
+
"capture-pipeline",
|
|
12957
|
+
"ingestion",
|
|
12958
|
+
"intelligence-and-operations",
|
|
12959
|
+
"review-and-learning",
|
|
12960
|
+
"general"
|
|
12961
|
+
];
|
|
13326
12962
|
var orientSchema = z22.object({
|
|
13327
12963
|
mode: z22.enum(["full", "brief"]).optional().default("full").describe("full = full context (default). brief = compact summary for mid-session re-orientation."),
|
|
13328
|
-
task: z22.string().optional().describe("Natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task.")
|
|
12964
|
+
task: z22.string().optional().describe("Natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task."),
|
|
12965
|
+
scope: z22.enum(VALID_TASK_DOMAINS).optional().describe(`Optional domain scope to filter governance to entries relevant for this domain. Valid values: ${VALID_TASK_DOMAINS.join(", ")}.`)
|
|
13329
12966
|
});
|
|
13330
12967
|
function taskGroundingWarningLines(task, hasTaskGrounding = false) {
|
|
13331
12968
|
if (hasTaskGrounding) return [];
|
|
@@ -13351,12 +12988,15 @@ function registerOrientTool(server) {
|
|
|
13351
12988
|
"orient",
|
|
13352
12989
|
{
|
|
13353
12990
|
title: "Orient \u2014 Start Here",
|
|
13354
|
-
description: "The single entry point for starting a session. Returns workspace context with a single recommended next action for low-readiness workspaces, or a standup-style briefing for established workspaces.\n\nUse this FIRST. One call to orient replaces 3\u20135 individual tool calls.\n\nCompleting orientation unlocks write tools for the active session.\n\n**mode:** `full` (default) returns full context. `brief` returns only vision, bet/tension counts, readiness, active bet names, and last-session summary \u2014 use for mid-session re-orientation.\n\n**task:** Optional natural-language task description. When provided, returns task-scoped context (scored, relevant entries) in addition to standard orient sections.",
|
|
12991
|
+
description: "The single entry point for starting a session. Returns workspace context with a single recommended next action for low-readiness workspaces, or a standup-style briefing for established workspaces.\n\nUse this FIRST. One call to orient replaces 3\u20135 individual tool calls.\n\nCompleting orientation unlocks write tools for the active session.\n\n**mode:** `full` (default) returns full context. `brief` returns only vision, bet/tension counts, readiness, active bet names, and last-session summary \u2014 use for mid-session re-orientation.\n\n**task:** Optional natural-language task description. When provided, returns task-scoped context (scored, relevant entries) in addition to standard orient sections.\n\n**scope:** Optional domain scope. Filters governance entries to those relevant for the specified domain. Valid values: auth, governance, architecture, product, data-foundation, chainwork, capture-pipeline, ingestion, intelligence-and-operations, review-and-learning, general.",
|
|
13355
12992
|
inputSchema: orientSchema,
|
|
13356
12993
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
13357
12994
|
},
|
|
13358
|
-
withEnvelope(async ({ mode = "full", task
|
|
12995
|
+
withEnvelope(async ({ mode = "full", task, scope }) => {
|
|
13359
12996
|
const errors = [];
|
|
12997
|
+
if (scope && !task) {
|
|
12998
|
+
errors.push("--scope requires --task to filter governance. Scope was ignored.");
|
|
12999
|
+
}
|
|
13360
13000
|
const agentSessionId = getAgentSessionId();
|
|
13361
13001
|
if (isSessionOriented() && mode === "brief" && !task) {
|
|
13362
13002
|
return {
|
|
@@ -13397,6 +13037,7 @@ function registerOrientTool(server) {
|
|
|
13397
13037
|
try {
|
|
13398
13038
|
const orientArgs = {};
|
|
13399
13039
|
if (task) orientArgs.task = task;
|
|
13040
|
+
if (scope) orientArgs.scope = scope;
|
|
13400
13041
|
if (sessionEntryIds.length > 0) orientArgs.sessionEntryIds = sessionEntryIds;
|
|
13401
13042
|
if (lastSessionOnly.length > 0) orientArgs.lastSessionEntryIds = lastSessionOnly;
|
|
13402
13043
|
orientEntries = await mcpQuery("chain.getOrientEntries", orientArgs);
|
|
@@ -14043,16 +13684,15 @@ function buildSessionSummary(log) {
|
|
|
14043
13684
|
}
|
|
14044
13685
|
return lines.join("\n");
|
|
14045
13686
|
}
|
|
14046
|
-
function computeOrganisationHealth(entries) {
|
|
13687
|
+
function computeOrganisationHealth(entries, classifications) {
|
|
14047
13688
|
let agreements = 0;
|
|
14048
13689
|
let disagreements = 0;
|
|
14049
13690
|
let abstentions = 0;
|
|
14050
13691
|
const flagMap = /* @__PURE__ */ new Map();
|
|
14051
|
-
for (
|
|
14052
|
-
const slug =
|
|
14053
|
-
const
|
|
14054
|
-
|
|
14055
|
-
if (!result) {
|
|
13692
|
+
for (let i = 0; i < entries.length; i++) {
|
|
13693
|
+
const slug = entries[i].collectionSlug ?? entries[i].collection ?? "unknown";
|
|
13694
|
+
const result = classifications[i];
|
|
13695
|
+
if (!result?.collection) {
|
|
14056
13696
|
abstentions++;
|
|
14057
13697
|
continue;
|
|
14058
13698
|
}
|
|
@@ -14092,7 +13732,15 @@ async function fetchOrganisationHealth() {
|
|
|
14092
13732
|
try {
|
|
14093
13733
|
const allEntries = await mcpQuery("chain.listEntries", { status: "active" });
|
|
14094
13734
|
if (!allEntries || allEntries.length === 0) return null;
|
|
14095
|
-
|
|
13735
|
+
const classifyInput = allEntries.map((e) => ({
|
|
13736
|
+
name: e.name ?? "",
|
|
13737
|
+
description: typeof e.data?.description === "string" ? e.data.description : ""
|
|
13738
|
+
}));
|
|
13739
|
+
const classifications = await mcpQuery(
|
|
13740
|
+
"chain.batchClassifyHeuristic",
|
|
13741
|
+
{ entries: classifyInput }
|
|
13742
|
+
);
|
|
13743
|
+
return computeOrganisationHealth(allEntries, classifications);
|
|
14096
13744
|
} catch (err) {
|
|
14097
13745
|
process.stderr.write(`[MCP] fetchOrganisationHealth failed: ${err.message}
|
|
14098
13746
|
`);
|
|
@@ -14260,7 +13908,7 @@ async function handleWorkspaceStatus() {
|
|
|
14260
13908
|
)
|
|
14261
13909
|
};
|
|
14262
13910
|
}
|
|
14263
|
-
async function
|
|
13911
|
+
async function handleAudit2(limit) {
|
|
14264
13912
|
const log = getAuditLog();
|
|
14265
13913
|
const recent = log.slice(-limit);
|
|
14266
13914
|
if (recent.length === 0) {
|
|
@@ -14453,7 +14101,7 @@ function registerHealthTools(server) {
|
|
|
14453
14101
|
if (action === "check") return handleHealthCheck();
|
|
14454
14102
|
if (action === "whoami") return handleWhoami();
|
|
14455
14103
|
if (action === "status") return handleWorkspaceStatus();
|
|
14456
|
-
if (action === "audit") return
|
|
14104
|
+
if (action === "audit") return handleAudit2(limit ?? 20);
|
|
14457
14105
|
if (action === "self-test") return handleSelfTest();
|
|
14458
14106
|
return unknownAction(action, HEALTH_ACTIONS);
|
|
14459
14107
|
});
|
|
@@ -15464,4 +15112,4 @@ export {
|
|
|
15464
15112
|
SERVER_VERSION,
|
|
15465
15113
|
createProductBrainServer
|
|
15466
15114
|
};
|
|
15467
|
-
//# sourceMappingURL=chunk-
|
|
15115
|
+
//# sourceMappingURL=chunk-CDBSOVW7.js.map
|