@productbrain/mcp 0.0.1-beta.3298 → 0.0.1-beta.3314

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.
@@ -40,7 +40,7 @@ import {
40
40
  trackSessionCaptureRate,
41
41
  trackWriteBackHintServed,
42
42
  trackZeroCaptureAuditFired
43
- } from "./chunk-6XYRKXER.js";
43
+ } from "./chunk-ZZVUTH6P.js";
44
44
 
45
45
  // src/server.ts
46
46
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -14706,6 +14706,168 @@ function registerFeedbackTool(server) {
14706
14706
  }));
14707
14707
  }
14708
14708
 
14709
+ // src/tools/shape.ts
14710
+ import { z as z29 } from "zod/v3";
14711
+ var SHAPE_ACTIONS = ["list", "show", "agree", "dismiss"];
14712
+ var LIST_DISPOSITIONS = ["pending", "agreed", "dismissed", "expired"];
14713
+ var LIST_OUTCOMES = ["not_candidate", "atomic", "compound", "unavailable"];
14714
+ var shapeSchema = z29.object({
14715
+ action: z29.enum(SHAPE_ACTIONS).describe(
14716
+ "'list': list shape advisories for this workspace, latest per subject. 'show': show one shape advisory by id. 'agree': agree with a compound advisory's split verdict. 'dismiss': dismiss a compound advisory's split verdict."
14717
+ ),
14718
+ disposition: z29.enum(LIST_DISPOSITIONS).optional().describe(
14719
+ "For 'list': filter by disposition. Omitting both disposition and outcome defaults to the actionable set (disposition:pending, outcome:compound)."
14720
+ ),
14721
+ outcome: z29.enum(LIST_OUTCOMES).optional().describe(
14722
+ "For 'list': filter by outcome. Omitting both disposition and outcome defaults to the actionable set (disposition:pending, outcome:compound)."
14723
+ ),
14724
+ limit: z29.number().min(1).max(200).optional().describe("For 'list': max rows (default 50, max 200)."),
14725
+ rowId: z29.string().max(200).optional().describe("For 'show'/'agree'/'dismiss': the advisory row id."),
14726
+ reason: z29.string().max(1e3).optional().describe("For 'agree'/'dismiss': optional reason (capped at 1000 chars).")
14727
+ });
14728
+ var shapeListVariant = z29.object({
14729
+ action: z29.literal("list"),
14730
+ disposition: z29.enum(LIST_DISPOSITIONS).optional(),
14731
+ outcome: z29.enum(LIST_OUTCOMES).optional(),
14732
+ limit: z29.number().min(1).max(200).optional()
14733
+ });
14734
+ var shapeShowVariant = z29.object({ action: z29.literal("show"), rowId: z29.string().max(200) });
14735
+ var shapeAgreeVariant = z29.object({ action: z29.literal("agree"), rowId: z29.string().max(200), reason: z29.string().max(1e3).optional() });
14736
+ var shapeDismissVariant = z29.object({ action: z29.literal("dismiss"), rowId: z29.string().max(200), reason: z29.string().max(1e3).optional() });
14737
+ var shapeActionUnion = z29.discriminatedUnion("action", [
14738
+ shapeListVariant,
14739
+ shapeShowVariant,
14740
+ shapeAgreeVariant,
14741
+ shapeDismissVariant
14742
+ ]);
14743
+ var SHAPE_ACTION_SPECS = {
14744
+ list: { params: ["disposition", "outcome", "limit"], description: "All params optional; no filters defaults to disposition:pending + outcome:compound." },
14745
+ show: { params: ["rowId"], description: "rowId is required." },
14746
+ agree: { params: ["rowId", "reason"], description: "rowId is required; reason is optional." },
14747
+ dismiss: { params: ["rowId", "reason"], description: "rowId is required; reason is optional." }
14748
+ };
14749
+ async function handleShapeList(disposition, outcome, limit) {
14750
+ const noFiltersGiven = disposition === void 0 && outcome === void 0;
14751
+ const effectiveDisposition = disposition ?? (noFiltersGiven ? "pending" : void 0);
14752
+ const effectiveOutcome = outcome ?? (noFiltersGiven ? "compound" : void 0);
14753
+ const items = await kernelQuery("chain.shapeAdvisories", {
14754
+ ...effectiveDisposition ? { disposition: effectiveDisposition } : {},
14755
+ ...effectiveOutcome ? { outcome: effectiveOutcome } : {},
14756
+ ...limit ? { limit } : {}
14757
+ });
14758
+ if (items.length === 0) {
14759
+ return successResult("No shape advisories match.", "No shape advisories found.", { items: [], count: 0 });
14760
+ }
14761
+ const lines = ["# Shape Advisories", ""];
14762
+ for (const item of items) {
14763
+ const verdict = item.outcome === "unavailable" && item.unavailableReason ? `unavailable(${item.unavailableReason})` : item.outcome;
14764
+ lines.push(`- \`${item.id}\` \u2014 ${item.subjectEntryId} \xB7 ${verdict} \xB7 disposition:${item.disposition} \xB7 ${item.source}`);
14765
+ }
14766
+ return successResult(
14767
+ lines.join("\n"),
14768
+ `Found ${items.length} shape advisor${items.length === 1 ? "y" : "ies"}.`,
14769
+ { items, count: items.length },
14770
+ [{ tool: "shape", description: "Show one advisory in full", parameters: { action: "show", rowId: items[0].id } }]
14771
+ );
14772
+ }
14773
+ function renderShapeAdvisoryText(item) {
14774
+ const lines = [
14775
+ `# ${item.id}`,
14776
+ `- Subject: ${item.subjectEntryId} (${item.collectionSlug})`,
14777
+ `- Outcome: ${item.outcome}`,
14778
+ `- Disposition: ${item.disposition}`,
14779
+ `- Source: ${item.source}`
14780
+ ];
14781
+ if (item.proposedAtoms?.length) {
14782
+ lines.push("", `Proposed split (${item.proposedAtoms.length} atom(s)):`);
14783
+ item.proposedAtoms.forEach((atom, idx) => {
14784
+ lines.push(` [${idx}] ${atom.title} \u2014 ${atom.concern}`);
14785
+ lines.push(` "${atom.bodyExcerpt}"`);
14786
+ if (atom.suggestedCollection) lines.push(` suggested collection: ${atom.suggestedCollection}`);
14787
+ });
14788
+ }
14789
+ if (item.proposedLinks?.length) {
14790
+ lines.push("", "Proposed links:");
14791
+ for (const link of item.proposedLinks) {
14792
+ const from = link.fromIdx === -1 ? "original" : `[${link.fromIdx}]`;
14793
+ lines.push(` ${from} --${link.relation}--> [${link.toIdx}]`);
14794
+ }
14795
+ }
14796
+ if (item.dispositionReason) lines.push("", `- Disposition reason: ${item.dispositionReason}`);
14797
+ return lines.join("\n");
14798
+ }
14799
+ async function handleShapeShow(rowId) {
14800
+ const item = await kernelQuery("chain.showShapeAdvisory", { rowId });
14801
+ if (!item) {
14802
+ return failureResult(
14803
+ `Advisory '${rowId}' not found (missing, or belongs to a different workspace).`,
14804
+ "NOT_FOUND",
14805
+ `Advisory '${rowId}' not found.`,
14806
+ "Use action=list to find valid ids.",
14807
+ [{ tool: "shape", description: "List advisories", parameters: { action: "list" } }]
14808
+ );
14809
+ }
14810
+ return successResult(
14811
+ renderShapeAdvisoryText(item),
14812
+ `Advisory ${item.id}: ${item.outcome}, disposition:${item.disposition}.`,
14813
+ item
14814
+ );
14815
+ }
14816
+ async function handleShapeDisposition(disposition, rowId, reason) {
14817
+ requireWriteAccess();
14818
+ try {
14819
+ const result2 = await kernelMutation("chain.dispositionShapeAdvisory", {
14820
+ rowId,
14821
+ disposition,
14822
+ ...reason ? { dispositionReason: reason } : {}
14823
+ });
14824
+ return successResult(
14825
+ `Advisory ${result2.rowId} dispositioned: ${result2.disposition}.`,
14826
+ `Advisory dispositioned: ${result2.disposition}.`,
14827
+ result2
14828
+ );
14829
+ } catch (err) {
14830
+ const classified = classifyError(err);
14831
+ const isNotFound = classified.code === "NOT_FOUND";
14832
+ return failureResult(
14833
+ classified.message,
14834
+ classified.code,
14835
+ classified.message,
14836
+ isNotFound ? "Use action=list to find valid ids." : classified.recovery ?? "Use action=show to check the advisory's current outcome/disposition.",
14837
+ isNotFound ? [{ tool: "shape", description: "List advisories", parameters: { action: "list" } }] : classified.availableActions ?? [{ tool: "shape", description: "Show the advisory", parameters: { action: "show", rowId } }],
14838
+ classified.diagnostics
14839
+ );
14840
+ }
14841
+ }
14842
+ function registerShapeTools(server) {
14843
+ const shapeHandlers = {
14844
+ list: (data) => handleShapeList(data.disposition, data.outcome, data.limit),
14845
+ show: (data) => handleShapeShow(data.rowId),
14846
+ agree: (data) => handleShapeDisposition("agreed", data.rowId, data.reason),
14847
+ dismiss: (data) => handleShapeDisposition("dismissed", data.rowId, data.reason)
14848
+ };
14849
+ server.registerTool(
14850
+ "shape",
14851
+ {
14852
+ title: "Shape",
14853
+ description: "Review and disposition shape-advisory (single-concern split) suggestions for this workspace. Four actions:\n\n- **list**: List shape advisories, latest per subject (filter by disposition/outcome).\n- **show**: Show one shape advisory in full by id.\n- **agree**: Agree with a compound advisory's split verdict.\n- **dismiss**: Dismiss a compound advisory's split verdict.",
14854
+ inputSchema: shapeSchema,
14855
+ // Mixed read/write noun (§3 R3, same as workspace's proposals-respond): agree/dismiss write;
14856
+ // list/show read.
14857
+ annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false }
14858
+ },
14859
+ thinWrapper(async (args) => {
14860
+ const parsed = parseOrFail(shapeSchema, args);
14861
+ if (!parsed.ok) return parsed.result;
14862
+ const { action } = parsed.data;
14863
+ return runWithToolContext(
14864
+ { tool: "shape", action },
14865
+ () => dispatchDiscriminated("shape", shapeActionUnion, parsed.data, SHAPE_ACTION_SPECS, shapeHandlers)
14866
+ );
14867
+ })
14868
+ );
14869
+ }
14870
+
14709
14871
  // src/resources/index.ts
14710
14872
  import { existsSync as existsSync3 } from "fs";
14711
14873
  import { dirname, join, resolve as resolve4 } from "path";
@@ -14715,7 +14877,7 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
14715
14877
  // src/resources/agentCheatsheet.ts
14716
14878
  var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
14717
14879
 
14718
- ## Core Tools (Serves 11 default compound tools; 3 more (chain, chain-review, map) behind PB_MODULES=gitchain)
14880
+ ## Core Tools (Serves 12 default compound tools; 3 more (chain, chain-review, map) behind PB_MODULES=gitchain)
14719
14881
  | Tool | Purpose | Key params |
14720
14882
  |---|---|---|
14721
14883
  | \`orient\` | Workspace context, governance, active bets, session start | \`action\`: start, task, record-activation |
@@ -14729,6 +14891,7 @@ var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
14729
14891
  | \`workflows\` | Run workflows, checkpoint, load a skill | \`action\`: list, start, checkpoint, get-run, load-skill |
14730
14892
  | \`workspace\` | Check / whoami / status / self-test, usage, governance proposals | \`action\`: check, whoami, status, audit, self-test, usage, proposals-* |
14731
14893
  | \`feedback\` | Submit product feedback (any key, no session required); \`list\` reads back your own workspace's feedback (no gate); vendor triage: queue / note / group / status | \`action\`: submit, list, queue, note, group, status |
14894
+ | \`shape\` | Review / disposition write-shape (single-concern split) advisories | \`action\`: list, show, agree, dismiss |
14732
14895
 
14733
14896
  ## Collection Prefixes
14734
14897
  GLO (glossary), BR (business-rules), PRI (principles), STD (standards),
@@ -15226,12 +15389,12 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
15226
15389
  }
15227
15390
 
15228
15391
  // src/prompts/index.ts
15229
- import { z as z29 } from "zod/v3";
15392
+ import { z as z30 } from "zod/v3";
15230
15393
  function registerPrompts(server) {
15231
15394
  server.prompt(
15232
15395
  "review-against-rules",
15233
15396
  "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.",
15234
- { domain: z29.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
15397
+ { domain: z30.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
15235
15398
  async ({ domain }) => {
15236
15399
  const entries = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
15237
15400
  const rules = entries.filter((e) => e.data?.domain === domain);
@@ -15284,7 +15447,7 @@ Provide a structured review with a compliance status for each rule (COMPLIANT /
15284
15447
  server.prompt(
15285
15448
  "name-check",
15286
15449
  "Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
15287
- { names: z29.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
15450
+ { names: z30.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
15288
15451
  async ({ names }) => {
15289
15452
  const terms = await kernelQuery("chain.listEntries", { collectionSlug: "glossary" });
15290
15453
  const glossaryContext = terms.map(
@@ -15320,7 +15483,7 @@ Format as a table: Name | Status | Canonical Form | Action Needed`
15320
15483
  server.prompt(
15321
15484
  "draft-decision-record",
15322
15485
  "Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
15323
- { context: z29.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
15486
+ { context: z30.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
15324
15487
  async ({ context }) => {
15325
15488
  const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
15326
15489
  const sorted = [...recentDecisions].sort((a, b) => (b.data?.date ?? "") > (a.data?.date ?? "") ? 1 : -1).slice(0, 5);
@@ -15358,8 +15521,8 @@ After drafting, I can log it using the capture tool with collection "decisions".
15358
15521
  "draft-rule-from-context",
15359
15522
  "Draft a new business rule from an observation or discovery made while coding. Fetches existing rules for the domain to ensure consistency.",
15360
15523
  {
15361
- observation: z29.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
15362
- domain: z29.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
15524
+ observation: z30.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
15525
+ domain: z30.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
15363
15526
  },
15364
15527
  async ({ observation, domain }) => {
15365
15528
  const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
@@ -15425,7 +15588,7 @@ var INSTRUCTIONS = [
15425
15588
  "- **Self-documenting**: orient and server instructions teach agents how PB works. Cursor rules supplement but don't replace.",
15426
15589
  "",
15427
15590
  "### Tool Rename Notice (WP-484 S3, one release)",
15428
- "Serves 11 default compound tools; 3 more (chain, chain-review, map) behind PB_MODULES=gitchain.",
15591
+ "Serves 12 default compound tools (WP-559 adds `shape` \u2014 review/disposition for write-shape advisories); 3 more (chain, chain-review, map) behind PB_MODULES=gitchain.",
15429
15592
  "Old standalone names are gone \u2014 no alias window (ASM-43: zero external consumers). Map: `start_pb`\u2192`orient action=start`, `record_activation`\u2192`orient action=record-activation`, `session-wrapup`\u2192`session action=wrapup-review|wrapup-commit`, `facilitate`\u2192`session action=resume|commit-constellation`, `update-entry`\u2192`entries action=update`, `commit-entry`\u2192`entries action=commit`, `get-history`\u2192`entries action=history`, `move-entry`\u2192`entries action=move`, `verify-entry`\u2192`entries action=verify`, `graph`\u2192`relations action=find|suggest`, `documents`\u2192`context action=last-verified-brief`, `labels`\u2192`collections action=label-*`, `verify`\u2192`quality action=verify-chain`, `audit`\u2192`quality action=audit`, `health`\u2192`workspace action=check|whoami|status|self-test`, `get-usage-summary`\u2192`workspace action=usage`, `governance-proposals`\u2192`workspace action=proposals-*`, `skills`\u2192`workflows action=load-skill`, `chain-version`\u2192`chain action=version.*`, `chain-branch`\u2192`chain-review action=branch.*`, `create-audience-map-set`/`map-slot`/`map-version`/`map-suggest`\u2192`map action=create-audience-set|slot.*|version.*|suggest`.",
15430
15593
  "",
15431
15594
  "## Your Workspace Principles",
@@ -15494,6 +15657,7 @@ function createProductBrainServer() {
15494
15657
  registerWorkflowTools(server);
15495
15658
  registerWorkspaceTools(server);
15496
15659
  registerFeedbackTool(server);
15660
+ registerShapeTools(server);
15497
15661
  if (enabledModules.has("gitchain")) registerGitChainTools(server);
15498
15662
  if (enabledModules.has("gitchain")) registerMapTools(server);
15499
15663
  registerResources(server);
@@ -15634,4 +15798,4 @@ export {
15634
15798
  createProductBrainServer,
15635
15799
  initFeatureFlags
15636
15800
  };
15637
- //# sourceMappingURL=chunk-WXBZFMDB.js.map
15801
+ //# sourceMappingURL=chunk-AWDYYGKN.js.map