@productbrain/mcp 0.0.1-beta.5533 → 0.0.1-beta.5547

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.
@@ -42,7 +42,7 @@ import {
42
42
  trackSessionCaptureRate,
43
43
  trackWriteBackHintServed,
44
44
  trackZeroCaptureAuditFired
45
- } from "./chunk-QWPXJ5WU.js";
45
+ } from "./chunk-O53EBDOP.js";
46
46
 
47
47
  // src/server.ts
48
48
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -15334,6 +15334,9 @@ function stripControlChars(str) {
15334
15334
  if (!str) return str;
15335
15335
  return str.replace(ANSI_AND_CONTROL_RE2, "");
15336
15336
  }
15337
+ function sanitizeSingleLineField(str) {
15338
+ return stripControlChars(str).replace(/\s+/g, " ").trim();
15339
+ }
15337
15340
 
15338
15341
  // src/tools/question.ts
15339
15342
  var QUESTION_ACTIONS = ["create", "adopt", "assign", "snooze", "decline", "answer", "force-close", "list"];
@@ -15598,6 +15601,93 @@ function registerQuestionTools(server) {
15598
15601
  );
15599
15602
  }
15600
15603
 
15604
+ // src/tools/role.ts
15605
+ import { z as z34 } from "zod/v3";
15606
+ var ROLE_ACTIONS = ["accountable"];
15607
+ var roleSchema = z34.object({
15608
+ action: z34.enum(ROLE_ACTIONS).describe("'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage."),
15609
+ roleId: z34.string().max(200).optional().describe("The role, by the human chain id `chain.getEntry` or `pb get` would print for it, or a raw entry id. Required for 'accountable'."),
15610
+ canonicalKey: z34.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
15611
+ limit: z34.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
15612
+ cursor: z34.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor.")
15613
+ });
15614
+ var accountableVariant = z34.object({
15615
+ action: z34.literal("accountable"),
15616
+ roleId: z34.string().max(200),
15617
+ canonicalKey: z34.string().max(200).optional(),
15618
+ limit: z34.number().int().positive().max(200).optional(),
15619
+ cursor: z34.number().optional()
15620
+ });
15621
+ var roleActionUnion = z34.discriminatedUnion("action", [accountableVariant]);
15622
+ var ROLE_ACTION_SPECS = {
15623
+ accountable: { params: ["roleId", "canonicalKey", "limit", "cursor"], description: "roleId is required; canonicalKey/limit/cursor are optional." }
15624
+ };
15625
+ function formatRow(row) {
15626
+ const id = row.entryId ?? row.id;
15627
+ return ` ${id} ${sanitizeSingleLineField(row.name)} [${row.canonicalKey ?? "?"}/${row.status}]`;
15628
+ }
15629
+ function formatSection(label, rows, truncated, cursorHint) {
15630
+ if (rows.length === 0) return [` ${label}: not recorded yet`];
15631
+ const lines = [` ${label}:`, ...rows.map(formatRow)];
15632
+ if (truncated) lines.push(` (more exist \u2014 ${cursorHint ?? "raise limit (capped at 200, no cursor for this list)"})`);
15633
+ return lines;
15634
+ }
15635
+ function formatRoleAccountable(result2) {
15636
+ const roleLabel = `${sanitizeSingleLineField(result2.role.name)} (${result2.role.entryId ?? result2.role.id})`;
15637
+ const explicitCursorHint = result2.nextCursor !== null ? `raise limit or continue with cursor ${result2.nextCursor}` : "raise limit";
15638
+ return [
15639
+ `${roleLabel} \u2014 accountability:`,
15640
+ ...formatSection("explicit (owns)", result2.explicit, result2.explicitTruncated, explicitCursorHint),
15641
+ ...formatSection("reporting (reports on)", result2.reporting, result2.reportingTruncated),
15642
+ ` inherited: not-computed \u2014 ${result2.inheritedNotComputedReason}`
15643
+ ].join("\n");
15644
+ }
15645
+ async function handleRoleAccountable(roleId, canonicalKey, limit, cursor) {
15646
+ try {
15647
+ const raw = await kernelQuery("chain.listByRole", { roleId, canonicalKey, limit, cursor });
15648
+ const result2 = raw;
15649
+ const message = formatRoleAccountable(result2);
15650
+ return successResult(message, message, result2);
15651
+ } catch (err) {
15652
+ return roleErrorResult(err, "accountable", { roleId, canonicalKey, limit, cursor });
15653
+ }
15654
+ }
15655
+ function roleErrorResult(err, action, params = {}) {
15656
+ const classified = classifyError(err);
15657
+ const definedParams = Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0));
15658
+ return failureResult(
15659
+ classified.message,
15660
+ classified.code,
15661
+ classified.message,
15662
+ classified.recovery ?? "Use action='accountable' with roleId set to a real role's chain id or entry id.",
15663
+ classified.availableActions ?? [{ tool: "role", description: `Retry ${action}`, parameters: { action, ...definedParams } }],
15664
+ classified.diagnostics
15665
+ );
15666
+ }
15667
+ function registerRoleTools(server) {
15668
+ const roleHandlers = {
15669
+ accountable: (data) => handleRoleAccountable(data.roleId, data.canonicalKey, data.limit, data.cursor)
15670
+ };
15671
+ server.registerTool(
15672
+ "role",
15673
+ {
15674
+ title: "Role",
15675
+ description: "Workspace roles \u2014 who is accountable for what. One action:\n\n- **accountable**: what this role owns (`explicit`, data.ownerRoleId), reports on (`reporting`, data.reporterRoleId \u2014 key results and tensions only, a separate fact from ownership), and \u2014 always `not-computed` today, never faked as empty \u2014 inherits via Team-Lead vacancy coverage.",
15676
+ inputSchema: roleSchema,
15677
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
15678
+ },
15679
+ thinWrapper(async (args) => {
15680
+ const parsed = parseOrFail(roleSchema, args);
15681
+ if (!parsed.ok) return parsed.result;
15682
+ const { action } = parsed.data;
15683
+ return runWithToolContext(
15684
+ { tool: "role", action },
15685
+ () => dispatchDiscriminated("role", roleActionUnion, parsed.data, ROLE_ACTION_SPECS, roleHandlers)
15686
+ );
15687
+ })
15688
+ );
15689
+ }
15690
+
15601
15691
  // src/resources/index.ts
15602
15692
  import { existsSync as existsSync3 } from "fs";
15603
15693
  import { dirname, join, resolve as resolve4 } from "path";
@@ -15607,7 +15697,7 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
15607
15697
  // src/resources/agentCheatsheet.ts
15608
15698
  var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
15609
15699
 
15610
- ## Core Tools (Serves 13 default compound tools; 2 more (chain, chain-review) behind PB_MODULES=gitchain \u2014 map retired, L29)
15700
+ ## Core Tools (Serves 14 default compound tools; 2 more (chain, chain-review) behind PB_MODULES=gitchain \u2014 map retired, L29)
15611
15701
  | Tool | Purpose | Key params |
15612
15702
  |---|---|---|
15613
15703
  | \`orient\` | Workspace context, governance, active work packages, session start | \`action\`: start, task, record-activation |
@@ -15623,6 +15713,7 @@ var AGENT_CHEATSHEET = `# Product Brain \u2014 Agent Cheatsheet
15623
15713
  | \`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 |
15624
15714
  | \`shape\` | Review / disposition write-shape (single-concern split) advisories | \`action\`: list, show, agree, dismiss |
15625
15715
  | \`question\` | Routed questions \u2014 create/adopt, own, snooze, decline, answer, force-close | \`action\`: create, adopt, assign, snooze, decline, answer, force-close |
15716
+ | \`role\` | What a role is accountable for \u2014 owns, reports on, and (not yet computed) inherits via Team-Lead vacancy coverage | \`action\`: accountable |
15626
15717
 
15627
15718
  ## Collection Prefixes
15628
15719
  GLO (glossary), BR (business-rules), PRI (principles), STD (standards),
@@ -16109,12 +16200,12 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
16109
16200
  }
16110
16201
 
16111
16202
  // src/prompts/index.ts
16112
- import { z as z34 } from "zod/v3";
16203
+ import { z as z35 } from "zod/v3";
16113
16204
  function registerPrompts(server) {
16114
16205
  server.prompt(
16115
16206
  "review-against-rules",
16116
16207
  "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.",
16117
- { domain: z34.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
16208
+ { domain: z35.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
16118
16209
  async ({ domain }) => {
16119
16210
  const entries = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
16120
16211
  const rules = entries.filter((e) => e.data?.domain === domain);
@@ -16167,7 +16258,7 @@ Provide a structured review with a compliance status for each rule (COMPLIANT /
16167
16258
  server.prompt(
16168
16259
  "name-check",
16169
16260
  "Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
16170
- { names: z34.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
16261
+ { names: z35.string().describe("Comma-separated list of names to check (e.g. 'vendor_id, compliance_level, formulator_type')") },
16171
16262
  async ({ names }) => {
16172
16263
  const terms = await kernelQuery("chain.listEntries", { collectionSlug: "glossary" });
16173
16264
  const glossaryContext = terms.map(
@@ -16203,7 +16294,7 @@ Format as a table: Name | Status | Canonical Form | Action Needed`
16203
16294
  server.prompt(
16204
16295
  "draft-decision-record",
16205
16296
  "Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
16206
- { context: z34.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
16297
+ { context: z35.string().describe("Description of the decision (e.g. 'We decided to use MRSL v3.1 as the conformance baseline because...')") },
16207
16298
  async ({ context }) => {
16208
16299
  const recentDecisions = await kernelQuery("chain.listEntries", { collectionSlug: "decisions" });
16209
16300
  const sorted = [...recentDecisions].sort((a, b) => (b.data?.date ?? "") > (a.data?.date ?? "") ? 1 : -1).slice(0, 5);
@@ -16241,8 +16332,8 @@ After drafting, I can log it using the capture tool with collection "decisions".
16241
16332
  "draft-rule-from-context",
16242
16333
  "Draft a new business rule from an observation or discovery made while coding. Fetches existing rules for the domain to ensure consistency.",
16243
16334
  {
16244
- observation: z34.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
16245
- domain: z34.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
16335
+ observation: z35.string().describe("What you observed or discovered (e.g. 'Suppliers can have multiple org types in Gateway')"),
16336
+ domain: z35.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
16246
16337
  },
16247
16338
  async ({ observation, domain }) => {
16248
16339
  const allRules = await kernelQuery("chain.listEntries", { collectionSlug: "business-rules" });
@@ -16308,7 +16399,7 @@ var INSTRUCTIONS = [
16308
16399
  "- **Self-documenting**: orient and server instructions teach agents how PB works. Cursor rules supplement but don't replace.",
16309
16400
  "",
16310
16401
  "### Tool Rename Notice (WP-484 S3, one release)",
16311
- "Serves 13 default compound tools (WP-559 adds `shape` \u2014 review/disposition for write-shape advisories; WP-638 S3 adds `question` \u2014 routed-question routing/ownership/lifecycle); 2 more (chain, chain-review) behind PB_MODULES=gitchain.",
16402
+ "Serves 14 default compound tools (WP-559 adds `shape` \u2014 review/disposition for write-shape advisories; WP-638 S3 adds `question` \u2014 routed-question routing/ownership/lifecycle; WP-730 S2 adds `role` \u2014 role accountability); 2 more (chain, chain-review) behind PB_MODULES=gitchain.",
16312
16403
  "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.*`.",
16313
16404
  "",
16314
16405
  "## Your Workspace Principles",
@@ -16380,6 +16471,7 @@ function createProductBrainServer() {
16380
16471
  registerFeedbackTool(server);
16381
16472
  registerShapeTools(server);
16382
16473
  registerQuestionTools(server);
16474
+ registerRoleTools(server);
16383
16475
  if (enabledModules.has("gitchain")) registerGitChainTools(server);
16384
16476
  registerResources(server);
16385
16477
  registerPrompts(server);
@@ -16519,4 +16611,4 @@ export {
16519
16611
  createProductBrainServer,
16520
16612
  initFeatureFlags
16521
16613
  };
16522
- //# sourceMappingURL=chunk-W3SWGAV4.js.map
16614
+ //# sourceMappingURL=chunk-N7Y43VJY.js.map