@productbrain/mcp 0.0.1-beta.134 → 0.0.1-beta.137

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,311 +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
- ];
1016
- var SIGNAL_WEIGHT = 10;
1017
- var MIN_SCORE_FLOOR = 10;
1018
- var MAX_MATCHES_PER_SIGNAL = 2;
1019
- var MAX_REASON_COUNT = 3;
1020
- var ENTRY_ID_PATTERN = /\b[A-Z]{2,}-\d+\b/g;
1021
- var COLLECTION_SIGNALS = {
1022
- decisions: [
1023
- "decide",
1024
- "decision",
1025
- "chose",
1026
- "chosen",
1027
- "choice",
1028
- "resolved",
1029
- "we will",
1030
- "we should",
1031
- "approved",
1032
- "replaces",
1033
- "instead of",
1034
- "go with",
1035
- "criteria",
1036
- "adopted",
1037
- "reposition",
1038
- "scoring framework",
1039
- "review",
1040
- // BET-124: tune recall 35%→≥50% — match abstained/misclassified fixture entries
1041
- "guard level",
1042
- "mcp-native",
1043
- "pure functions",
1044
- "intentional debt",
1045
- "read allowlist",
1046
- "safe-by-default",
1047
- "map ingredients",
1048
- "never per-seat",
1049
- "neighborhood-first",
1050
- "locked at",
1051
- "ssot"
1052
- ],
1053
- tensions: [
1054
- "problem",
1055
- "issue",
1056
- "blocked",
1057
- "blocker",
1058
- "friction",
1059
- "pain",
1060
- "bottleneck",
1061
- "struggle",
1062
- "missing",
1063
- "breaks",
1064
- "regression",
1065
- "unclear",
1066
- "no way to",
1067
- "scope creep",
1068
- "coupled",
1069
- "trapped",
1070
- "ambiguous",
1071
- "no batch",
1072
- "undetectable",
1073
- "coordination gap",
1074
- // BET-124: tune recall 40%→≥50% — match abstained/misclassified fixture entries
1075
- "methodology wall",
1076
- "feature flag gap",
1077
- "doesn't bridge",
1078
- "cap limits",
1079
- "trapped in",
1080
- "no pan",
1081
- "no zoom",
1082
- "no interaction",
1083
- "accuracy regression",
1084
- "response bloat"
1085
- ],
1086
- glossary: [
1087
- "definition",
1088
- "define",
1089
- "term",
1090
- "means",
1091
- "refers to",
1092
- "defined as",
1093
- "is a term for",
1094
- "is called",
1095
- "vocabulary",
1096
- "terminology",
1097
- "a governance mechanism",
1098
- "a workspace",
1099
- "a tracked",
1100
- "the atom",
1101
- "the action of",
1102
- "the versioned",
1103
- "a field on",
1104
- "one of the",
1105
- "a constraint on",
1106
- "a hard data",
1107
- "a single",
1108
- // BET-124: tune recall 46.7%→≥50% — definitional language, name-is-term pattern
1109
- "constraint"
1110
- ],
1111
- insights: [
1112
- "insight",
1113
- "learned",
1114
- "observed",
1115
- "trend",
1116
- "found that",
1117
- "discovery",
1118
- "validates",
1119
- "validated",
1120
- "saturates",
1121
- "convergence",
1122
- "signals from",
1123
- "signals",
1124
- "converge",
1125
- "tam",
1126
- // BET-124: tune recall 26.7%→≥40% — research/data/learning language
1127
- "thesis",
1128
- "decay",
1129
- "learnings",
1130
- "aha moment",
1131
- "data informs"
1132
- ],
1133
- features: [
1134
- "feature",
1135
- "capability",
1136
- "user can",
1137
- "navigation",
1138
- "palette",
1139
- "modal",
1140
- "smart capture",
1141
- "suggest-links",
1142
- "command palette",
1143
- "auto-commit",
1144
- "collection-optional",
1145
- "organisation intelligence",
1146
- "consolidation"
1147
- ],
1148
- architecture: [
1149
- "architecture",
1150
- "layer",
1151
- "data model",
1152
- "infrastructure",
1153
- "system design",
1154
- "l1",
1155
- "l2",
1156
- "l3",
1157
- "l4",
1158
- "l5",
1159
- "l6",
1160
- "l7",
1161
- "guard infrastructure",
1162
- "data layer",
1163
- "intelligence layer",
1164
- "mcp layer",
1165
- "core layer"
1166
- ],
1167
- "business-rules": [
1168
- "guard",
1169
- "enforce",
1170
- "integrity",
1171
- "prevents",
1172
- "excludes",
1173
- "permitted",
1174
- "policy",
1175
- "feature gate",
1176
- "must not",
1177
- "only permitted",
1178
- "closed enum",
1179
- "write guard",
1180
- "never imports",
1181
- "requires active session",
1182
- "readiness excludes"
1183
- ],
1184
- // tracking-events: removed (Tier 1 Hierarchy — 0 entries, collection deprecated)
1185
- landscape: [
1186
- "competitor",
1187
- "alternative tool",
1188
- "alternative platform",
1189
- "competing product",
1190
- "landscape",
1191
- "comparison"
1192
- ],
1193
- standards: [
1194
- "standard",
1195
- "convention",
1196
- "trunk-based",
1197
- "alignment-first",
1198
- "structured bet",
1199
- "system fixes",
1200
- "patches"
1201
- ],
1202
- principles: [
1203
- "we believe",
1204
- "principle",
1205
- "compounds",
1206
- "philosophy",
1207
- "simplicity compounds",
1208
- "trust through",
1209
- "evidence over",
1210
- "compensate for",
1211
- "honest by default"
1212
- ],
1213
- assumptions: [
1214
- "assume",
1215
- "assumption",
1216
- "hypothesis",
1217
- "untested",
1218
- "we think",
1219
- "we assume",
1220
- "needs validation"
1221
- ],
1222
- patterns: [
1223
- "pattern",
1224
- "anti-pattern",
1225
- "best practice",
1226
- "reusable solution",
1227
- "design pattern",
1228
- "recurring solution",
1229
- "template",
1230
- "proven approach"
1231
- ],
1232
- "work-packages": [
1233
- "appetite",
1234
- "elements",
1235
- "no-gos",
1236
- "no gos",
1237
- "problem",
1238
- "solution",
1239
- "done when",
1240
- "doneWhen",
1241
- "rabbit hole",
1242
- "rabbit holes",
1243
- "build sequence",
1244
- "build contract",
1245
- "slice",
1246
- "bet",
1247
- "shaping",
1248
- "shape up"
1249
- ]
1250
- };
1251
- function escapeRegExp(text) {
1252
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1253
- }
1254
- function countSignalMatches(text, signal) {
1255
- const trimmed = signal.trim().toLowerCase();
1256
- if (!trimmed) return 0;
1257
- const words = trimmed.split(/\s+/).map(escapeRegExp);
1258
- const pattern = `\\b${words.join("\\s+")}\\b`;
1259
- const regex = new RegExp(pattern, "g");
1260
- const matches = text.match(regex);
1261
- return matches?.length ?? 0;
1262
- }
1263
- function classifyCollection(name, description) {
1264
- const text = `${name} ${description}`.replace(ENTRY_ID_PATTERN, "").toLowerCase();
1265
- const rawScores = [];
1266
- for (const collection of CLASSIFIABLE_COLLECTIONS) {
1267
- const signals = COLLECTION_SIGNALS[collection];
1268
- const reasons = [];
1269
- let score = 0;
1270
- for (const signal of signals) {
1271
- const matches = countSignalMatches(text, signal);
1272
- if (matches <= 0) continue;
1273
- const cappedMatches = Math.min(matches, MAX_MATCHES_PER_SIGNAL);
1274
- score += cappedMatches * SIGNAL_WEIGHT;
1275
- if (reasons.length < MAX_REASON_COUNT) {
1276
- const capNote = matches > cappedMatches ? ` (capped at ${cappedMatches})` : "";
1277
- reasons.push(`matched "${signal}" x${matches}${capNote}`);
1278
- }
1279
- }
1280
- rawScores.push({ collection, score, reasons });
1281
- }
1282
- rawScores.sort((left, right) => right.score - left.score);
1283
- const top = rawScores[0];
1284
- const second = rawScores[1];
1285
- if (!top || top.score < MIN_SCORE_FLOOR) return null;
1286
- const margin = Math.max(0, top.score - (second?.score ?? 0));
1287
- if (margin === 0 && top.score <= MIN_SCORE_FLOOR) return null;
1288
- const baseConfidence = Math.min(90, top.score);
1289
- const confidence = Math.min(99, baseConfidence + Math.min(20, margin));
1290
- return {
1291
- collection: top.collection,
1292
- topConfidence: confidence,
1293
- confidence,
1294
- reasons: top.reasons,
1295
- scoreMargin: margin,
1296
- candidates: rawScores.filter((candidate) => candidate.score > 0).slice(0, 3).map((candidate) => ({
1297
- collection: candidate.collection,
1298
- signalScore: Math.min(99, candidate.score),
1299
- confidence: Math.min(99, candidate.score)
1300
- }))
1301
- };
1302
- }
1303
-
1304
999
  // src/tools/smart-capture.ts
1305
1000
  function normalizeMatchText(value) {
1306
1001
  return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").replace(/\s+/g, " ").trim();
@@ -13308,9 +13003,23 @@ function extractSessionEntryIds(priorSessions) {
13308
13003
  }
13309
13004
  return { all, lastSessionOnly };
13310
13005
  }
13006
+ var VALID_TASK_DOMAINS = [
13007
+ "auth",
13008
+ "governance",
13009
+ "architecture",
13010
+ "product",
13011
+ "data-foundation",
13012
+ "chainwork",
13013
+ "capture-pipeline",
13014
+ "ingestion",
13015
+ "intelligence-and-operations",
13016
+ "review-and-learning",
13017
+ "general"
13018
+ ];
13311
13019
  var orientSchema = z22.object({
13312
13020
  mode: z22.enum(["full", "brief"]).optional().default("full").describe("full = full context (default). brief = compact summary for mid-session re-orientation."),
13313
- task: z22.string().optional().describe("Natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task.")
13021
+ task: z22.string().optional().describe("Natural-language task description for task-scoped context. When provided, orient returns scored, relevant entries for the task."),
13022
+ 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(", ")}.`)
13314
13023
  });
13315
13024
  function taskGroundingWarningLines(task, hasTaskGrounding = false) {
13316
13025
  if (hasTaskGrounding) return [];
@@ -13336,12 +13045,15 @@ function registerOrientTool(server) {
13336
13045
  "orient",
13337
13046
  {
13338
13047
  title: "Orient \u2014 Start Here",
13339
- 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.",
13048
+ 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.",
13340
13049
  inputSchema: orientSchema,
13341
13050
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
13342
13051
  },
13343
- withEnvelope(async ({ mode = "full", task } = {}) => {
13052
+ withEnvelope(async ({ mode = "full", task, scope }) => {
13344
13053
  const errors = [];
13054
+ if (scope && !task) {
13055
+ errors.push("--scope requires --task to filter governance. Scope was ignored.");
13056
+ }
13345
13057
  const agentSessionId = getAgentSessionId();
13346
13058
  if (isSessionOriented() && mode === "brief" && !task) {
13347
13059
  return {
@@ -13382,6 +13094,7 @@ function registerOrientTool(server) {
13382
13094
  try {
13383
13095
  const orientArgs = {};
13384
13096
  if (task) orientArgs.task = task;
13097
+ if (scope) orientArgs.scope = scope;
13385
13098
  if (sessionEntryIds.length > 0) orientArgs.sessionEntryIds = sessionEntryIds;
13386
13099
  if (lastSessionOnly.length > 0) orientArgs.lastSessionEntryIds = lastSessionOnly;
13387
13100
  orientEntries = await mcpQuery("chain.getOrientEntries", orientArgs);
@@ -14028,16 +13741,15 @@ function buildSessionSummary(log) {
14028
13741
  }
14029
13742
  return lines.join("\n");
14030
13743
  }
14031
- function computeOrganisationHealth(entries) {
13744
+ function computeOrganisationHealth(entries, classifications) {
14032
13745
  let agreements = 0;
14033
13746
  let disagreements = 0;
14034
13747
  let abstentions = 0;
14035
13748
  const flagMap = /* @__PURE__ */ new Map();
14036
- for (const entry of entries) {
14037
- const slug = entry.collectionSlug ?? entry.collection ?? "unknown";
14038
- const description = typeof entry.data?.description === "string" ? entry.data.description : "";
14039
- const result = classifyCollection(entry.name, description);
14040
- if (!result) {
13749
+ for (let i = 0; i < entries.length; i++) {
13750
+ const slug = entries[i].collectionSlug ?? entries[i].collection ?? "unknown";
13751
+ const result = classifications[i];
13752
+ if (!result?.collection) {
14041
13753
  abstentions++;
14042
13754
  continue;
14043
13755
  }
@@ -14077,7 +13789,15 @@ async function fetchOrganisationHealth() {
14077
13789
  try {
14078
13790
  const allEntries = await mcpQuery("chain.listEntries", { status: "active" });
14079
13791
  if (!allEntries || allEntries.length === 0) return null;
14080
- return computeOrganisationHealth(allEntries);
13792
+ const classifyInput = allEntries.map((e) => ({
13793
+ name: e.name ?? "",
13794
+ description: typeof e.data?.description === "string" ? e.data.description : ""
13795
+ }));
13796
+ const classifications = await mcpQuery(
13797
+ "chain.batchClassifyHeuristic",
13798
+ { entries: classifyInput }
13799
+ );
13800
+ return computeOrganisationHealth(allEntries, classifications);
14081
13801
  } catch (err) {
14082
13802
  process.stderr.write(`[MCP] fetchOrganisationHealth failed: ${err.message}
14083
13803
  `);
@@ -15449,4 +15169,4 @@ export {
15449
15169
  SERVER_VERSION,
15450
15170
  createProductBrainServer
15451
15171
  };
15452
- //# sourceMappingURL=chunk-UUUJXF2W.js.map
15172
+ //# sourceMappingURL=chunk-YKDHYK3Q.js.map