@productbrain/mcp 0.0.1-beta.137 → 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.
@@ -1701,7 +1701,9 @@ var batchCaptureSchema = z2.object({
1701
1701
  description: z2.string().describe("Full context / definition"),
1702
1702
  entryId: entryIdSchema,
1703
1703
  data: z2.record(z2.unknown()).optional().describe("Explicit field values (e.g. urgency, status, assignee). Merged with inferred values; user-provided wins."),
1704
- 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.")
1705
1707
  })).min(1).max(50).describe("Array of entries to capture"),
1706
1708
  autoCommit: z2.boolean().optional().describe(
1707
1709
  "If true, commits created entries immediately after linking. If omitted, Open mode workspaces commit by default and consensus/role modes stay draft-first."
@@ -2878,7 +2880,9 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
2878
2880
  data,
2879
2881
  createdBy,
2880
2882
  sessionId: agentId ?? void 0,
2881
- canonicalKey: entry.canonicalKey ?? void 0
2883
+ canonicalKey: entry.canonicalKey ?? void 0,
2884
+ ...entry.sourceRef ? { sourceRef: entry.sourceRef } : {},
2885
+ ...entry.sourceExcerpt ? { sourceExcerpt: entry.sourceExcerpt } : {}
2882
2886
  });
2883
2887
  const internalId = result.docId;
2884
2888
  const finalEntryId = result.entryId;
@@ -3457,7 +3461,9 @@ var updateEntrySchema = z3.object({
3457
3461
  order: z3.number().optional().describe("New sort order"),
3458
3462
  canonicalKey: z3.string().optional().describe("Semantic type (e.g. 'decision', 'tension'). Only changeable on draft/uncommitted entries."),
3459
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."),
3460
- 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.")
3461
3467
  });
3462
3468
  var getHistorySchema = z3.object({
3463
3469
  entryId: z3.string().describe("Entry ID, e.g. 'T-SUPPLIER', 'BR-001'")
@@ -3474,7 +3480,7 @@ function registerKnowledgeTools(server) {
3474
3480
  inputSchema: updateEntrySchema,
3475
3481
  annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false }
3476
3482
  },
3477
- 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 }) => {
3478
3484
  requireWriteAccess();
3479
3485
  const PROMOTED_FIELDS = ["status", "workflowStatus", "name", "order", "canonicalKey"];
3480
3486
  const topLevelByField = { status: rawStatus, workflowStatus: rawWorkflowStatus, name, order, canonicalKey };
@@ -3513,7 +3519,9 @@ function registerKnowledgeTools(server) {
3513
3519
  canonicalKey,
3514
3520
  autoPublish,
3515
3521
  changeNote,
3516
- changedBy: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0
3522
+ changedBy: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
3523
+ ...sourceRef ? { sourceRef } : {},
3524
+ ...sourceExcerpt ? { sourceExcerpt } : {}
3517
3525
  });
3518
3526
  const id = updateResult.id;
3519
3527
  await recordSessionActivity({ entryModified: id });
@@ -5834,7 +5842,7 @@ function formatTimeAgo(ms) {
5834
5842
 
5835
5843
  // src/tools/collections.ts
5836
5844
  import { z as z8 } from "zod";
5837
- var COLLECTIONS_ACTIONS = ["list", "create", "update", "describe"];
5845
+ var COLLECTIONS_ACTIONS = ["list", "create", "update", "describe", "audit"];
5838
5846
  var qualityCriterionSchema = z8.object({
5839
5847
  field: z8.string().describe("Entry data field key this criterion applies to, e.g. 'description', 'owner'"),
5840
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)."),
@@ -5860,7 +5868,7 @@ var fieldSchema = z8.object({
5860
5868
  });
5861
5869
  var collectionsSchema = z8.object({
5862
5870
  action: z8.enum(COLLECTIONS_ACTIONS).describe(
5863
- "'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."
5864
5872
  ),
5865
5873
  slug: z8.string().optional().describe("URL-safe identifier for create/update, e.g. 'glossary', 'tech-debt'"),
5866
5874
  name: z8.string().optional().describe("Display name for create, or new name for update"),
@@ -5883,7 +5891,7 @@ function registerCollectionsTools(server) {
5883
5891
  "collections",
5884
5892
  {
5885
5893
  title: "Collections",
5886
- 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.",
5887
5895
  inputSchema: collectionsSchema,
5888
5896
  annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
5889
5897
  },
@@ -5917,6 +5925,9 @@ function registerCollectionsTools(server) {
5917
5925
  }
5918
5926
  return handleUpdate(slug, name, description, purpose, icon, navGroup, fields, { defaultCanonicalKey, defaultWorkflowStatus, validWorkflowStatuses, classificationCheck, classificationPriority, qualityCriteria, usageGuidance });
5919
5927
  }
5928
+ if (action === "audit") {
5929
+ return handleAudit();
5930
+ }
5920
5931
  return unknownAction(action, COLLECTIONS_ACTIONS);
5921
5932
  });
5922
5933
  })
@@ -6145,6 +6156,44 @@ Use \`collections action=list\` to verify the result.`
6145
6156
  )
6146
6157
  };
6147
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
+ }
6148
6197
 
6149
6198
  // src/tools/labels.ts
6150
6199
  import { z as z9 } from "zod";
@@ -6283,14 +6332,7 @@ import { z as z10 } from "zod";
6283
6332
  // src/lib/coherence/data.ts
6284
6333
  var REGISTRY_MANIFEST = [
6285
6334
  // ── Canonical UI registries ──────────────────────────────────────
6286
- {
6287
- id: "ui-colors",
6288
- path: "src/lib/utils/collection-colors.ts",
6289
- exportName: "COLLECTION_COLORS",
6290
- description: "CSS color mapping for UI components",
6291
- expectedCoverage: "curated",
6292
- keyExtraction: "object-keys"
6293
- },
6335
+ // BET-143 Slice 4: ui-colors removed — color is now a field on collection docs (schema.ts).
6294
6336
  {
6295
6337
  id: "routes",
6296
6338
  path: "src/lib/navigation.ts",
@@ -6307,56 +6349,11 @@ var REGISTRY_MANIFEST = [
6307
6349
  expectedCoverage: "curated",
6308
6350
  keyExtraction: "object-keys"
6309
6351
  },
6310
- {
6311
- id: "sidebar-collections",
6312
- path: "src/lib/navigation.ts",
6313
- exportName: "SIDEBAR_COLLECTION_SLUGS",
6314
- description: "Collection slugs with dedicated sidebar entries",
6315
- expectedCoverage: "subset",
6316
- keyExtraction: "set-values"
6317
- },
6318
- {
6319
- id: "display-fields",
6320
- path: "src/lib/components/EntryPreviewModal.svelte",
6321
- exportName: "DISPLAY_FIELDS",
6322
- description: "Fields displayed in entry preview modal per collection",
6323
- expectedCoverage: "curated",
6324
- keyExtraction: "object-keys"
6325
- },
6326
- // ── Brain Chat registries ────────────────────────────────────────
6327
- {
6328
- id: "brain-colors",
6329
- path: "src/lib/components/brain/brain-types.ts",
6330
- exportName: "COLLECTION_COLORS",
6331
- description: "Brain Chat collection color palette",
6332
- expectedCoverage: "subset",
6333
- keyExtraction: "object-keys"
6334
- },
6335
- {
6336
- id: "brain-icons",
6337
- path: "src/lib/components/brain/brain-types.ts",
6338
- exportName: "COLLECTION_ICONS",
6339
- description: "Brain Chat collection icons",
6340
- expectedCoverage: "subset",
6341
- keyExtraction: "object-keys"
6342
- },
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.
6343
6354
  // ── Graph visualization registries ───────────────────────────────
6344
- {
6345
- id: "graph-colors",
6346
- path: "src/lib/utils/graphToVisNetwork.ts",
6347
- exportName: "GRAPH_COLLECTION_COLORS",
6348
- description: "Graph visualization hex color palette",
6349
- expectedCoverage: "subset",
6350
- keyExtraction: "object-keys"
6351
- },
6352
- {
6353
- id: "graph-type-colors",
6354
- path: "src/lib/components/graph/graph.types.ts",
6355
- exportName: "COLLECTION_COLORS",
6356
- description: "Chain Graph collection colors (distinct palette)",
6357
- expectedCoverage: "subset",
6358
- keyExtraction: "object-keys"
6359
- },
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).
6360
6357
  // ── Cortex registries ────────────────────────────────────────────
6361
6358
  {
6362
6359
  id: "renderers",
@@ -6378,71 +6375,17 @@ var REGISTRY_MANIFEST = [
6378
6375
  // TEN-598: default-collections removed. Collection definitions live in system_collection_definitions (DB).
6379
6376
  ];
6380
6377
  var COLLECTION_REGISTRY_RULES = [
6381
- // ── Coverage: downstream registries should cover important collections ──
6382
- {
6383
- id: "coverage-ui-colors",
6384
- type: "coverage",
6385
- description: "UI colors should cover collections that have sidebar routes",
6386
- subject: "ui-colors",
6387
- reference: "routes"
6388
- },
6389
6378
  // ── Subset: specialized registries should only reference known collections ──
6390
- {
6391
- id: "subset-brain-colors",
6392
- type: "subset",
6393
- description: "Brain colors should only reference classified collections",
6394
- subject: "brain-colors",
6395
- reference: "classification-map"
6396
- },
6397
- {
6398
- id: "subset-brain-icons",
6399
- type: "subset",
6400
- description: "Brain icons should only reference classified collections",
6401
- subject: "brain-icons",
6402
- reference: "classification-map"
6403
- },
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.
6404
6383
  {
6405
6384
  id: "subset-renderers",
6406
6385
  type: "subset",
6407
6386
  description: "Renderers should only reference classified collections",
6408
6387
  subject: "renderers",
6409
6388
  reference: "classification-map"
6410
- },
6411
- {
6412
- id: "subset-display-fields",
6413
- type: "subset",
6414
- description: "Display fields should only reference classified collections",
6415
- subject: "display-fields",
6416
- reference: "classification-map"
6417
- },
6418
- {
6419
- id: "subset-graph-colors",
6420
- type: "subset",
6421
- description: "Graph colors should only reference classified collections",
6422
- subject: "graph-colors",
6423
- reference: "classification-map"
6424
- },
6425
- {
6426
- id: "subset-graph-type-colors",
6427
- type: "subset",
6428
- description: "Graph type colors should only reference classified collections",
6429
- subject: "graph-type-colors",
6430
- reference: "classification-map"
6431
- },
6432
- // ── Implication: presence in one registry implies presence in another ──
6433
- {
6434
- id: "implication-routes-need-colors",
6435
- type: "implication",
6436
- description: "Collections with routes should also have UI colors",
6437
- subject: "routes",
6438
- reference: "ui-colors"
6439
- },
6440
- {
6441
- id: "implication-sidebar-needs-route",
6442
- type: "implication",
6443
- description: "Sidebar collections should have a route defined",
6444
- subject: "sidebar-collections",
6445
- reference: "routes"
6446
6389
  }
6447
6390
  ];
6448
6391
 
@@ -13965,7 +13908,7 @@ async function handleWorkspaceStatus() {
13965
13908
  )
13966
13909
  };
13967
13910
  }
13968
- async function handleAudit(limit) {
13911
+ async function handleAudit2(limit) {
13969
13912
  const log = getAuditLog();
13970
13913
  const recent = log.slice(-limit);
13971
13914
  if (recent.length === 0) {
@@ -14158,7 +14101,7 @@ function registerHealthTools(server) {
14158
14101
  if (action === "check") return handleHealthCheck();
14159
14102
  if (action === "whoami") return handleWhoami();
14160
14103
  if (action === "status") return handleWorkspaceStatus();
14161
- if (action === "audit") return handleAudit(limit ?? 20);
14104
+ if (action === "audit") return handleAudit2(limit ?? 20);
14162
14105
  if (action === "self-test") return handleSelfTest();
14163
14106
  return unknownAction(action, HEALTH_ACTIONS);
14164
14107
  });
@@ -15169,4 +15112,4 @@ export {
15169
15112
  SERVER_VERSION,
15170
15113
  createProductBrainServer
15171
15114
  };
15172
- //# sourceMappingURL=chunk-YKDHYK3Q.js.map
15115
+ //# sourceMappingURL=chunk-CDBSOVW7.js.map